diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee13ae71..d0884dab 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ This can usually be solved either by adding a new filename or file name extensio Assuming your code is being detected as the right language (see above), in most cases this is due to a bug in the language grammar rather than a bug in Linguist. [`grammars.yml`][grammars] lists all the grammars we use for syntax highlighting on github.com. Find the one corresponding to your code's programming language and submit a bug report upstream. -You can also try to fix the bug yourself and submit a Pull Request. [This piece from TextMate's documentation](http://manual.macromates.com/en/language_grammars) offers a good introduction on how to work with TextMate-compatible grammars. +You can also try to fix the bug yourself and submit a Pull Request. [This piece from TextMate's documentation](http://manual.macromates.com/en/language_grammars) offers a good introduction on how to work with TextMate-compatible grammars. You can test grammars using [Lightshow](https://lightshow.githubapp.com). Once the bug has been fixed upstream, please let us know and we'll pick it up for GitHub. diff --git a/Gemfile b/Gemfile index 481a4c6e..95769569 100644 --- a/Gemfile +++ b/Gemfile @@ -2,3 +2,4 @@ source 'https://rubygems.org' gemspec :name => "github-linguist" gemspec :name => "github-linguist-grammars" gem 'test-unit', require: false if RUBY_VERSION >= '2.2' +gem 'byebug' if RUBY_VERSION >= '2.0' diff --git a/grammars.yml b/grammars.yml index fbf087d3..1bedce80 100644 --- a/grammars.yml +++ b/grammars.yml @@ -5,8 +5,6 @@ http://svn.textmate.org/trunk/Review/Bundles/BlitzMax.tmbundle: - source.blitzmax http://svn.textmate.org/trunk/Review/Bundles/Cython.tmbundle: - source.cython -http://svn.textmate.org/trunk/Review/Bundles/F%20Sharp.tmbundle: -- source.fsharp http://svn.textmate.org/trunk/Review/Bundles/Forth.tmbundle: - source.forth http://svn.textmate.org/trunk/Review/Bundles/Parrot.tmbundle: @@ -63,8 +61,14 @@ https://github.com/Varriount/NimLime: - source.nimrod - source.nimrod_filter - source.nimrodcfg +https://github.com/alkemist/gradle.tmbundle: +- source.groovy.gradle +https://github.com/ambethia/Sublime-Loom: +- source.loomscript https://github.com/angryant0007/VBDotNetSyntax: - source.vbnet +https://github.com/anunayk/cool-tmbundle: +- source.cool https://github.com/aroben/ada.tmbundle/raw/c45eed4d5f98fe3bcbbffbb9e436601ab5bbde4b/Syntaxes/Ada.plist: - source.ada https://github.com/aroben/ruby.tmbundle@4636a3023153c3034eb6ffc613899ba9cf33b41f: @@ -135,6 +139,8 @@ https://github.com/euler0/sublime-glsl/raw/master/GLSL.tmLanguage: - source.glsl https://github.com/fancy-lang/fancy-tmbundle: - source.fancy +https://github.com/fsharp/fsharpbinding: +- source.fsharp https://github.com/gingerbeardman/monkey.tmbundle: - source.monkey https://github.com/guillermooo/dart-sublime-bundle/raw/master/Dart.tmLanguage: @@ -163,6 +169,8 @@ https://github.com/lavrton/sublime-better-typescript: - source.ts https://github.com/leafo/moonscript-tmbundle: - source.moonscript +https://github.com/lsf37/Isabelle.tmbundle: +- source.isabelle.theory https://github.com/lunixbochs/x86-assembly-textmate-bundle: - source.asm.x86 https://github.com/macekond/Alloy.tmbundle: @@ -408,3 +416,7 @@ https://github.com/vmg/zephir-sublime: - source.php.zephir https://github.com/whitequark/llvm.tmbundle: - source.llvm +https://github.com/wmertens/sublime-nix: +- source.nix +https://raw.githubusercontent.com/eregon/oz-tmbundle/master/Syntaxes/Oz.tmLanguage: +- source.oz diff --git a/lib/linguist.rb b/lib/linguist.rb index 3714b5a0..ff9fc3a2 100644 --- a/lib/linguist.rb +++ b/lib/linguist.rb @@ -4,4 +4,5 @@ require 'linguist/heuristics' require 'linguist/language' require 'linguist/repository' require 'linguist/samples' +require 'linguist/shebang' require 'linguist/version' diff --git a/lib/linguist/classifier.rb b/lib/linguist/classifier.rb index 5370bdd8..89a0df2f 100644 --- a/lib/linguist/classifier.rb +++ b/lib/linguist/classifier.rb @@ -3,6 +3,25 @@ require 'linguist/tokenizer' module Linguist # Language bayesian classifier. class Classifier + # Public: Use the classifier to detect language of the blob. + # + # blob - An object that quacks like a blob. + # possible_languages - Array of Language objects + # + # Examples + # + # Classifier.call(FileBlob.new("path/to/file"), [ + # Language["Ruby"], Language["Python"] + # ]) + # + # Returns an Array of Language objects, most probable first. + def self.call(blob, possible_languages) + language_names = possible_languages.map(&:name) + classify(Samples.cache, blob.data, language_names).map do |name, _| + Language[name] # Return the actual Language objects + end + end + # Public: Train classifier that data is a certain language. # # db - Hash classifier database object diff --git a/lib/linguist/file_blob.rb b/lib/linguist/file_blob.rb index bc475023..04441935 100644 --- a/lib/linguist/file_blob.rb +++ b/lib/linguist/file_blob.rb @@ -57,14 +57,20 @@ module Linguist # # Returns a String. def extension - # File.extname returns nil if the filename is an extension. - extension = File.extname(name) - basename = File.basename(name) - # Checks if the filename is an extension. - if extension.empty? && basename[0] == "." - basename - else - extension + extensions.last || "" + end + + # Public: Return an array of the file extensions + # + # >> Linguist::FileBlob.new("app/views/things/index.html.erb").extensions + # => [".html.erb", ".erb"] + # + # Returns an Array + def extensions + basename, *segments = File.basename(name).split(".") + + segments.map.with_index do |segment, index| + "." + segments[index..-1].join(".") end end end diff --git a/lib/linguist/heuristics.rb b/lib/linguist/heuristics.rb index 13f0173f..c496b8f8 100644 --- a/lib/linguist/heuristics.rb +++ b/lib/linguist/heuristics.rb @@ -1,158 +1,160 @@ module Linguist # A collection of simple heuristics that can be used to better analyze languages. class Heuristics - ACTIVE = true - - # Public: Given an array of String language names, - # apply heuristics against the given data and return an array - # of matching languages, or nil. + # Public: Use heuristics to detect language of the blob. # - # data - Array of tokens or String data to analyze. - # languages - Array of language name Strings to restrict to. + # blob - An object that quacks like a blob. + # possible_languages - Array of Language objects # - # Returns an array of Languages or [] - def self.find_by_heuristics(data, languages) - if active? - result = [] + # Examples + # + # Heuristics.call(FileBlob.new("path/to/file"), [ + # Language["Ruby"], Language["Python"] + # ]) + # + # Returns an Array of languages, or empty if none matched or were inconclusive. + def self.call(blob, languages) + data = blob.data - if languages.all? { |l| ["Perl", "Prolog"].include?(l) } - result = disambiguate_pl(data) - end - if languages.all? { |l| ["ECL", "Prolog"].include?(l) } - result = disambiguate_ecl(data) - end - if languages.all? { |l| ["IDL", "Prolog"].include?(l) } - result = disambiguate_pro(data) - end - if languages.all? { |l| ["Common Lisp", "OpenCL"].include?(l) } - result = disambiguate_cl(data) - end - if languages.all? { |l| ["Hack", "PHP"].include?(l) } - result = disambiguate_hack(data) - end - if languages.all? { |l| ["Scala", "SuperCollider"].include?(l) } - result = disambiguate_sc(data) - end - if languages.all? { |l| ["AsciiDoc", "AGS Script"].include?(l) } - result = disambiguate_asc(data) - end - if languages.all? { |l| ["FORTRAN", "Forth"].include?(l) } - result = disambiguate_f(data) - end - return result + @heuristics.each do |heuristic| + return Array(heuristic.call(data)) if heuristic.matches?(languages) + end + + [] # No heuristics matched + end + + # Internal: Define a new heuristic. + # + # languages - String names of languages to disambiguate. + # heuristic - Block which takes data as an argument and returns a Language or nil. + # + # Examples + # + # disambiguate "Perl", "Prolog" do |data| + # if data.include?("use strict") + # Language["Perl"] + # elsif data.include?(":-") + # Language["Prolog"] + # end + # end + # + def self.disambiguate(*languages, &heuristic) + @heuristics << new(languages, &heuristic) + end + + # Internal: Array of defined heuristics + @heuristics = [] + + # Internal + def initialize(languages, &heuristic) + @languages = languages + @heuristic = heuristic + end + + # Internal: Check if this heuristic matches the candidate languages. + def matches?(candidates) + candidates.any? && candidates.all? { |l| @languages.include?(l.name) } + end + + # Internal: Perform the heuristic + def call(data) + @heuristic.call(data) + end + + disambiguate "Objective-C", "C++", "C" do |data| + if (/@(interface|class|protocol|property|end|synchronised|selector|implementation)\b/.match(data)) + Language["Objective-C"] + elsif (/^\s*#\s*include <(cstdint|string|vector|map|list|array|bitset|queue|stack|forward_list|unordered_map|unordered_set|(i|o|io)stream)>/.match(data) || + /^\s*template\s*") - matches << Language["C++"] - end - matches - end - - def self.disambiguate_pl(data) - matches = [] - if data.include?("use strict") - matches << Language["Perl"] + disambiguate "Perl", "Perl6", "Prolog" do |data| + if data.include?("use v6") + Language["Perl6"] + elsif data.include?("use strict") + Language["Perl"] elsif data.include?(":-") - matches << Language["Prolog"] + Language["Prolog"] end - matches end - def self.disambiguate_ecl(data) - matches = [] + disambiguate "ECL", "Prolog" do |data| if data.include?(":-") - matches << Language["Prolog"] + Language["Prolog"] elsif data.include?(":=") - matches << Language["ECL"] + Language["ECL"] end - matches end - def self.disambiguate_pro(data) - matches = [] - if (data.include?(":-")) - matches << Language["Prolog"] + disambiguate "IDL", "Prolog" do |data| + if data.include?(":-") + Language["Prolog"] else - matches << Language["IDL"] + Language["IDL"] end - matches end - def self.disambiguate_ts(data) - matches = [] - if (data.include?("")) - matches << Language["XML"] - else - matches << Language["TypeScript"] - end - matches - end - - def self.disambiguate_cl(data) - matches = [] + disambiguate "Common Lisp", "OpenCL", "Cool" do |data| if data.include?("(defun ") - matches << Language["Common Lisp"] + Language["Common Lisp"] + elsif /^class/x.match(data) + Language["Cool"] elsif /\/\* |\/\/ |^\}/.match(data) - matches << Language["OpenCL"] + Language["OpenCL"] end - matches end - def self.disambiguate_r(data) - matches = [] - matches << Language["Rebol"] if /\bRebol\b/i.match(data) - matches << Language["R"] if data.include?("<-") - matches - end - - def self.disambiguate_hack(data) - matches = [] + disambiguate "Hack", "PHP" do |data| if data.include?(" 1 - data = blob.data - possible_language_names = possible_languages.map(&:name) - heuristic_languages = Heuristics.find_by_heuristics(data, possible_language_names) - - if heuristic_languages.size > 1 - possible_language_names = heuristic_languages.map(&:name) + # Call each strategy until one candidate is returned. + STRATEGIES.reduce([]) do |languages, strategy| + candidates = strategy.call(blob, languages) + if candidates.size == 1 + return candidates.first + elsif candidates.size > 1 + # More than one candidate was found, pass them to the next strategy. + candidates + else + # No candiates were found, pass on languages from the previous strategy. + languages end - - # Check if there's a shebang line and use that as authoritative - if (result = find_by_shebang(data)) && !result.empty? - result.first - # No shebang. Still more work to do. Try to find it with our heuristics. - elsif heuristic_languages.size == 1 - heuristic_languages.first - # Lastly, fall back to the probabilistic classifier. - elsif classified = Classifier.classify(Samples.cache, data, possible_language_names).first - # Return the actual Language object based of the string language name (i.e., first element of `#classify`) - Language[classified[0]] - end - else - # Simplest and most common case, we can just return the one match based on extension - possible_languages.first - end + end.first end # Public: Get all Languages @@ -190,8 +172,13 @@ module Linguist # Returns all matching Languages or [] if none were found. def self.find_by_filename(filename) basename = File.basename(filename) - extname = FileBlob.new(filename).extension - (@filename_index[basename] + find_by_extension(extname)).compact.uniq + + # find the first extension with language definitions + extname = FileBlob.new(filename).extensions.detect do |e| + !@extension_index[e].empty? + end + + (@filename_index[basename] + @extension_index[extname]).compact.uniq end # Public: Look up Languages by file extension. @@ -212,20 +199,26 @@ module Linguist @extension_index[extname] end - # Public: Look up Languages by shebang line. + # DEPRECATED + def self.find_by_shebang(data) + @interpreter_index[Shebang.interpreter(data)] + end + + # Public: Look up Languages by interpreter. # - # data - Array of tokens or String data to analyze. + # interpreter - String of interpreter name # # Examples # - # Language.find_by_shebang("#!/bin/bash\ndate;") + # Language.find_by_interpreter("bash") # # => [#] # # Returns the matching Language - def self.find_by_shebang(data) - @interpreter_index[Linguist.interpreter_from_shebang(data)] + def self.find_by_interpreter(interpreter) + @interpreter_index[interpreter] end + # Public: Look up Language by its name or lexer. # # name - The String name of the Language diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index ea1991c8..e940ba93 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -308,6 +308,8 @@ C: color: "#555" extensions: - .c + - .C + - .H - .cats - .h - .idc @@ -335,9 +337,6 @@ C++: - cpp extensions: - .cpp - - .C - - .CPP - - .H - .c++ - .cc - .cxx @@ -528,6 +527,12 @@ Component Pascal: - delphi - objectpascal +Cool: + type: programming + extensions: + - .cl + tm_scope: source.cool + Coq: type: programming extensions: @@ -559,6 +564,8 @@ Crystal: - .cr ace_mode: ruby tm_scope: source.ruby + interpreters: + - crystal Cucumber: extensions: @@ -736,6 +743,8 @@ Erlang: - .es - .escript - .hrl + interpreters: + - escript F#: type: programming @@ -815,6 +824,7 @@ Forth: - .for - .forth - .frt + - .fs Frege: type: programming @@ -868,6 +878,7 @@ GLSL: - .fp - .frag - .frg + - .fs - .fshader - .geo - .geom @@ -931,6 +942,8 @@ Gnuplot: - .gnuplot - .plot - .plt + interpreters: + - gnuplot Go: type: programming @@ -961,6 +974,12 @@ Grace: - .grace tm_scope: none +Gradle: + type: data + extensions: + - .gradle + tm_scope: source.groovy.gradle + Grammatical Framework: type: programming aliases: @@ -1196,13 +1215,15 @@ Ioke: color: "#078193" extensions: - .ik + interpreters: + - ioke Isabelle: type: programming color: "#fdcd00" extensions: - .thy - tm_scope: none + tm_scope: source.isabelle.theory J: type: programming @@ -1288,6 +1309,7 @@ JavaScript: - .bones - .es6 - .frag + - .gs - .jake - .jsb - .jsfl @@ -1470,6 +1492,12 @@ LookML: - .lookml tm_scope: source.yaml +LoomScript: + type: programming + extensions: + - .ls + tm_scope: source.loomscript + Lua: type: programming ace_mode: lua @@ -1594,6 +1622,8 @@ Mercury: type: programming color: "#abcdef" ace_mode: prolog + interpreters: + - mmi extensions: - .m - .moo @@ -1687,11 +1717,12 @@ Nit: Nix: type: programming + color: "#7070ff" extensions: - .nix aliases: - nixos - tm_scope: none + tm_scope: source.nix Nu: type: programming @@ -1703,6 +1734,8 @@ Nu: filenames: - Nukefile tm_scope: source.scheme + interpreters: + - nush NumPy: group: Python @@ -1832,6 +1865,13 @@ Oxygene: - .oxygene tm_scope: none +Oz: + type: programming + color: "#fcaf3e" + extensions: + - .oz + tm_scope: source.oz + PAWN: type: programming color: "#dbb284" @@ -1849,7 +1889,6 @@ PHP: - .aw - .ctp - .fcgi - - .module - .php3 - .php4 - .php5 @@ -1889,6 +1928,8 @@ Parrot Assembly: - pasm extensions: - .pasm + interpreters: + - parrot tm_scope: none Parrot Internal Representation: @@ -1899,6 +1940,8 @@ Parrot Internal Representation: - pir extensions: - .pir + interpreters: + - parrot Pascal: type: programming @@ -1933,14 +1976,19 @@ Perl6: type: programming color: "#0298c3" extensions: - - .p6 - .6pl - .6pm - .nqp + - .p6 - .p6l - .p6m + - .pl - .pl6 + - .pm - .pm6 + - .t + interpreters: + - perl6 tm_scope: none PigLatin: @@ -2005,6 +2053,8 @@ Prolog: - .ecl - .pro - .prolog + interpreters: + - swipl Propeller Spin: type: programming @@ -2068,6 +2118,8 @@ Python: - wscript interpreters: - python + - python2 + - python3 Python traceback: type: data @@ -2088,6 +2140,8 @@ QMake: extensions: - .pro - .pri + interpreters: + - qmake R: type: programming @@ -2107,6 +2161,15 @@ R: interpreters: - Rscript +RAML: + type: data + lexer: YAML + ace_mode: yaml + tm_scope: source.yaml + color: "#77d9fb" + extensions: + - .raml + RDoc: type: prose ace_mode: rdoc @@ -2242,6 +2305,8 @@ Ruby: - .watchr interpreters: - ruby + - macruby + - rake filenames: - .pryrc - Appraisals @@ -2318,7 +2383,6 @@ Sass: group: CSS extensions: - .sass - - .scss Scala: type: programming @@ -2328,6 +2392,8 @@ Scala: - .scala - .sbt - .sc + interpreters: + - scala Scaml: group: HTML @@ -2718,6 +2784,7 @@ XML: - .jelly - .kml - .launch + - .mm - .mxml - .nproj - .nuspec diff --git a/lib/linguist/samples.rb b/lib/linguist/samples.rb index 82c011b1..2d389443 100644 --- a/lib/linguist/samples.rb +++ b/lib/linguist/samples.rb @@ -6,6 +6,7 @@ end require 'linguist/md5' require 'linguist/classifier' +require 'linguist/shebang' module Linguist # Model for accessing classifier training data. @@ -52,14 +53,16 @@ module Linguist }) end else + path = File.join(dirname, filename) + if File.extname(filename) == "" - raise "#{File.join(dirname, filename)} is missing an extension, maybe it belongs in filenames/ subdir" + raise "#{path} is missing an extension, maybe it belongs in filenames/ subdir" end yield({ - :path => File.join(dirname, filename), + :path => path, :language => category, - :interpreter => File.exist?(filename) ? Linguist.interpreter_from_shebang(File.read(filename)) : nil, + :interpreter => Shebang.interpreter(File.read(path)), :extname => File.extname(filename) }) end @@ -112,40 +115,4 @@ module Linguist db end end - - # Used to retrieve the interpreter from the shebang line of a file's - # data. - def self.interpreter_from_shebang(data) - lines = data.lines.to_a - - if lines.any? && (match = lines[0].match(/(.+)\n?/)) && (bang = match[0]) =~ /^#!/ - bang.sub!(/^#! /, '#!') - tokens = bang.split(' ') - pieces = tokens.first.split('/') - - if pieces.size > 1 - script = pieces.last - else - script = pieces.first.sub('#!', '') - end - - script = script == 'env' ? tokens[1] : script - - # "python2.6" -> "python" - if script =~ /((?:\d+\.?)+)/ - script.sub! $1, '' - end - - # Check for multiline shebang hacks that call `exec` - if script == 'sh' && - lines[0...5].any? { |l| l.match(/exec (\w+).+\$0.+\$@/) } - script = $1 - end - - script - else - nil - end - end - end diff --git a/lib/linguist/shebang.rb b/lib/linguist/shebang.rb new file mode 100644 index 00000000..3405bb62 --- /dev/null +++ b/lib/linguist/shebang.rb @@ -0,0 +1,44 @@ +module Linguist + class Shebang + # Public: Use shebang to detect language of the blob. + # + # blob - An object that quacks like a blob. + # + # Examples + # + # Shebang.call(FileBlob.new("path/to/file")) + # + # Returns an Array with one Language if the blob has a shebang with a valid + # interpreter, or empty if there is no shebang. + def self.call(blob, _ = nil) + Language.find_by_interpreter interpreter(blob.data) + end + + # Public: Get the interpreter from the shebang + # + # Returns a String or nil + def self.interpreter(data) + lines = data.lines + return unless match = /^#! ?(.+)$/.match(lines.first) + + tokens = match[1].split(' ') + script = tokens.first.split('/').last + + script = tokens[1] if script == 'env' + + # If script has an invalid shebang, we might get here + return unless script + + # "python2.6" -> "python2" + script.sub! $1, '' if script =~ /(\.\d+)$/ + + # Check for multiline shebang hacks that call `exec` + if script == 'sh' && + lines.first(5).any? { |l| l.match(/exec (\w+).+\$0.+\$@/) } + script = $1 + end + + File.basename(script) + end + end +end diff --git a/lib/linguist/strategy/filename.rb b/lib/linguist/strategy/filename.rb new file mode 100644 index 00000000..e682863b --- /dev/null +++ b/lib/linguist/strategy/filename.rb @@ -0,0 +1,20 @@ +module Linguist + module Strategy + # Detects language based on filename and/or extension + class Filename + def self.call(blob, _) + name = blob.name.to_s + + # A bit of an elegant hack. If the file is executable but extensionless, + # append a "magic" extension so it can be classified with other + # languages that have shebang scripts. + extensions = FileBlob.new(name).extensions + if extensions.empty? && blob.mode && (blob.mode.to_i(8) & 05) == 05 + name += ".script!" + end + + Language.find_by_filename(name) + end + end + end +end diff --git a/lib/linguist/vendor.yml b/lib/linguist/vendor.yml index 31ff7ce7..a68f0a81 100644 --- a/lib/linguist/vendor.yml +++ b/lib/linguist/vendor.yml @@ -232,9 +232,6 @@ # .DS_Store's - .[Dd][Ss]_[Ss]tore$ -# Mercury --use-subdirs -- Mercury/ - # R packages - ^vignettes/ - ^inst/extdata/ diff --git a/lib/linguist/version.rb b/lib/linguist/version.rb index 6aa2f696..45fb0292 100644 --- a/lib/linguist/version.rb +++ b/lib/linguist/version.rb @@ -1,3 +1,3 @@ module Linguist - VERSION = "4.0.3" + VERSION = "4.2.3" end diff --git a/samples/C++/16F88.h b/samples/C++/16F88.h new file mode 100644 index 00000000..28f51ce4 --- /dev/null +++ b/samples/C++/16F88.h @@ -0,0 +1,86 @@ +/* + * This file is part of PIC + * Copyright © 2012 Rachel Mant (dx-mon@users.sourceforge.net) + * + * PIC is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PIC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +enum PIC16F88Instruction +{ + ADDWF, + ANDWF, + CLRF, + CLRW, + COMF, + DECF, + DECFSZ, + INCF, + INCFSZ, + IORWF, + MOVF, + MOVWF, + NOP, + RLF, + RRF, + SUBWF, + SWAPF, + XORWF, + BCF, + BSF, + BTFSC, + BTFSS, + ADDLW, + ANDLW, + CALL, + CLRWDT, + GOTO, + IORLW, + MOVLW, + RETFIE, + RETLW, + RETURN, + SLEEP, + SUBLW, + XORLW +}; + +class PIC16F88 +{ +public: + PIC16F88(ROM *ProgramMemory); + void Step(); + +private: + uint8_t q; + bool nextIsNop, trapped; + Memory *memory; + ROM *program; + Stack *CallStack; + Register *PC; + Register<> *WREG, *PCL, *STATUS, *PCLATCH; + PIC16F88Instruction inst; + uint16_t instrWord; + +private: + void DecodeInstruction(); + void ProcessInstruction(); + + uint8_t GetBank(); + uint8_t GetMemoryContents(uint8_t partialAddress); + void SetMemoryContents(uint8_t partialAddress, uint8_t newVal); + void CheckZero(uint8_t value); + void StoreValue(uint8_t value, bool updateZero); + uint8_t SetCarry(bool val); + uint16_t GetPCHFinalBits(); +}; diff --git a/samples/C++/Memory16F88.h b/samples/C++/Memory16F88.h new file mode 100644 index 00000000..ced2ef13 --- /dev/null +++ b/samples/C++/Memory16F88.h @@ -0,0 +1,32 @@ +/* + * This file is part of PIC + * Copyright © 2012 Rachel Mant (dx-mon@users.sourceforge.net) + * + * PIC is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PIC is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "Memory.h" + +class Memory16F88 : public Memory +{ +private: + uint8_t memory[512]; + std::map memoryMap; + +public: + Memory16F88(); + uint8_t Dereference(uint8_t bank, uint8_t partialAddress); + uint8_t *Reference(uint8_t bank, uint8_t partialAddress); + uint8_t *operator [](uint32_t ref); +}; diff --git a/samples/C++/ThreadedQueue.h b/samples/C++/ThreadedQueue.h new file mode 100644 index 00000000..6b2fbaad --- /dev/null +++ b/samples/C++/ThreadedQueue.h @@ -0,0 +1,76 @@ +/* + * This file is part of IRCBot + * Copyright © 2014 Rachel Mant (dx-mon@users.sourceforge.net) + * + * IRCBot is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * IRCBot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __THREADED_QUEUE_H__ +#define __THREADED_QUEUE_H__ + +#include +#include + +template +class ThreadedQueue : public std::queue +{ +private: + pthread_mutex_t queueMutex; + pthread_cond_t queueCond; + +public: + ThreadedQueue() + { + pthread_mutexattr_t mutexAttrs; + pthread_condattr_t condAttrs; + + pthread_mutexattr_init(&mutexAttrs); + pthread_mutexattr_settype(&mutexAttrs, PTHREAD_MUTEX_ERRORCHECK); + pthread_mutex_init(&queueMutex, &mutexAttrs); + pthread_mutexattr_destroy(&mutexAttrs); + + pthread_condattr_init(&condAttrs); + pthread_condattr_setpshared(&condAttrs, PTHREAD_PROCESS_PRIVATE); + pthread_cond_init(&queueCond, &condAttrs); + pthread_condattr_destroy(&condAttrs); + } + + ~ThreadedQueue() + { + pthread_cond_destroy(&queueCond); + pthread_mutex_destroy(&queueMutex); + } + + void waitItems() + { + pthread_mutex_lock(&queueMutex); + pthread_cond_wait(&queueCond, &queueMutex); + pthread_mutex_unlock(&queueMutex); + } + + void signalItems() + { + pthread_mutex_lock(&queueMutex); + pthread_cond_broadcast(&queueCond); + pthread_mutex_unlock(&queueMutex); + } + + void push(T item) + { + std::queue::push(item); + signalItems(); + } +}; + +#endif /*__THREADED_QUEUE_H__*/ diff --git a/samples/C/2D.C b/samples/C/2D.C new file mode 100644 index 00000000..b3d45015 --- /dev/null +++ b/samples/C/2D.C @@ -0,0 +1,145 @@ +#include "2D.h" +#include + +void set_vgabasemem(void) +{ + ULONG vgabase; + SELECTOR tmp; + asm mov [tmp], ds + dpmi_get_sel_base(&vgabase, tmp); + vgabasemem = (char *)(-vgabase + 0xa0000); +} + +void drw_chdis(int mode) // change the display! +{ + regs.b.ah = 0x00; // seet theh display moode + regs.b.al = mode; // change it to the mode like innit + regs.h.flags = 0x72;// Set the dingoes kidneys out of FLAGS eh? + regs.h.ss = 0; // Like, totally set the stack segment + regs.h.sp = 0; // Set tha stack pointaaaaahhhhh!!! + dpmi_simulate_real_interrupt(0x10, ®s); +} + +void drw_pix(int x, int y, enum COLORS col) +{ + *VGAPIX(x, y) = col; +} + +void drw_line(int x0, int y0, int x1, int y1, enum COLORS col) +{ + // Going for the optimized version of bresenham's line algo. + int stp = (abs(y0 - y1) > abs(x0 - x1)); + int tmp, dx, dy, err, yi, i, j; // yi = y excrement + if (stp) { + // swappity swap + tmp = y0; + y0 = x0; + x0 = tmp; + + tmp = y1; + y1 = x1; + x1 = tmp; + } + // AAAAND NOW WE MUST DO ZEES AGAIN :( + // I'm sure there was a func somewhere that does this? :P + if (x0 > x1) { + tmp = x0; + x0 = x1; + x1 = tmp; + + tmp = y0; + y0 = y1; + y1 = tmp; + } + dx = (x1 - x0); + dy = (abs(y1 - y0)); + err = (dx / 2); + + if (y0 < y1) + yi = 1; + else + yi = -1; + j = y0; + for (i = x0; i < x1; i++) + { + if (stp) + *VGAPIX(j, i) = col; + else + *VGAPIX(i, j) = col; + + err -= dy; + if (err < 0) { + j += yi; + err += dx; + } + } +} + +void drw_rectl(int x, int y, int w, int h, enum COLORS col) +{ + drw_line(x, y, x+w, y, col); + drw_line(x+w, y, x+w, y+h, col); + + drw_line(x, y, x, y+h, col); + drw_line(x, y+h, x+w+1, y+h, col); +} + +void drw_rectf(int x, int y, int w, int h, enum COLORS col) +{ + int i, j; + for (j = y; j < x+h; j++) { + for (i = x; i < y+w; i++) { + *VGAPIX(i, j) = col; + } + } +} + +void drw_circl(int x, int y, int rad, enum COLORS col) +{ + int mang, i; // max angle, haha + int px, py; + mang = 360; // Yeah yeah I'll switch to rad later + for (i = 0; i <= mang; i++) + { + px = cos(i)*rad + x; // + px; // causes some really cools effects! :D + py = sin(i)*rad + y; // + py; + *VGAPIX(px, py) = col; + } +} + +void drw_tex(int x, int y, int w, int h, enum COLORS tex[]) +{ // i*w+j + int i, j; + for (i = 0; i < w; i++) + { + for (j = 0; j < h; j++) + { + *VGAPIX(x+i, y+j) = tex[j*w+i]; + } + } +} + +void 2D_init(void) +{ + set_vgabasemem(); + drw_chdis(0x13); +} + +void 2D_exit(void) +{ + drw_chdis(3); +} +/* +int main() +{ + set_vgabasemem(); + drw_chdis(0x13); + + while(!kbhit()) { + if ((getch()) == 0x1b) // escape + break; + } + drw_chdis(3); + return 0; +} +*/ diff --git a/samples/C/2D.H b/samples/C/2D.H new file mode 100644 index 00000000..e3354986 --- /dev/null +++ b/samples/C/2D.H @@ -0,0 +1,29 @@ +#ifndef __2DGFX +#define __2DGFX +// Includes +#include +#include +#include +#include + +// Defines +#define VGAPIX(x,y) (vgabasemem + (x) + (y) * 320) + +// Variables +char * vgabasemem; +DPMI_REGS regs; + +// Drawing functions: +//void setvgabasemem(void); +void drw_chdis(int mode); // draw_func_change_display +void drw_pix(int x, int y, enum COLORS col); +void drw_line(int x0, int y0, int x1, int y1, enum COLORS col); +void drw_rectl(int x, int y, int w, int h, enum COLORS col); +void drw_rectf(int x, int y, int w, int h, enum COLORS col); +void drw_cirl(int x, int y, int rad, enum COLORS col); +void drw_tex(int x, int y, int w, int h, enum COLORS tex[]); +void 2D_init(void); +void 2D_exit(void); + + +#endif diff --git a/samples/C/ArrowLeft.h b/samples/C/ArrowLeft.h new file mode 100644 index 00000000..b3577c0e --- /dev/null +++ b/samples/C/ArrowLeft.h @@ -0,0 +1,93 @@ +/* + * This file is part of GTK++ (libGTK++) + * Copyright © 2012 Rachel Mant (dx-mon@users.sourceforge.net) + * + * GTK++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GTK++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/* GdkPixbuf RGBA C-Source image dump */ + +#ifdef __SUNPRO_C +#pragma align 4 (ArrowLeft) +#endif +#ifdef __GNUC__ +static const uint8_t ArrowLeft[] __attribute__ ((__aligned__ (4))) = +#else +static const uint8_t ArrowLeft[] = +#endif +{ "" + /* Pixbuf magic (0x47646b50) */ + "GdkP" + /* length: header (24) + pixel_data (1600) */ + "\0\0\6X" + /* pixdata_type (0x1010002) */ + "\1\1\0\2" + /* rowstride (80) */ + "\0\0\0P" + /* width (20) */ + "\0\0\0\24" + /* height (20) */ + "\0\0\0\24" + /* pixel_data: */ + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\377\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0"}; + + diff --git a/samples/C/GLKMatrix4.h b/samples/C/GLKMatrix4.h new file mode 100644 index 00000000..41eb5afd --- /dev/null +++ b/samples/C/GLKMatrix4.h @@ -0,0 +1,903 @@ +// +// GLKMatrix4.h +// GLKit +// +// Copyright (c) 2011, Apple Inc. All rights reserved. +// + +#ifndef __GLK_MATRIX_4_H +#define __GLK_MATRIX_4_H + +#include +#include +#include + +#if defined(__ARM_NEON__) +#include +#endif + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma mark - +#pragma mark Prototypes +#pragma mark - + +extern const GLKMatrix4 GLKMatrix4Identity; + +/* + m30, m31, and m32 correspond to the translation values tx, ty, tz, respectively. + */ +static __inline__ GLKMatrix4 GLKMatrix4Make(float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33); + +/* + m03, m13, and m23 correspond to the translation values tx, ty, tz, respectively. + */ +static __inline__ GLKMatrix4 GLKMatrix4MakeAndTranspose(float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33); + +/* + m[12], m[13], and m[14] correspond to the translation values tx, ty, and tz, respectively. + */ +static __inline__ GLKMatrix4 GLKMatrix4MakeWithArray(float values[16]); + +/* + m[3], m[7], and m[11] correspond to the translation values tx, ty, and tz, respectively. + */ +static __inline__ GLKMatrix4 GLKMatrix4MakeWithArrayAndTranspose(float values[16]); + +/* + row0, row1, and row2's last component should correspond to the translation values tx, ty, and tz, respectively. + */ +static __inline__ GLKMatrix4 GLKMatrix4MakeWithRows(GLKVector4 row0, + GLKVector4 row1, + GLKVector4 row2, + GLKVector4 row3); + +/* + column3's first three components should correspond to the translation values tx, ty, and tz. + */ +static __inline__ GLKMatrix4 GLKMatrix4MakeWithColumns(GLKVector4 column0, + GLKVector4 column1, + GLKVector4 column2, + GLKVector4 column3); + +/* + The quaternion will be normalized before conversion. + */ +static __inline__ GLKMatrix4 GLKMatrix4MakeWithQuaternion(GLKQuaternion quaternion); + +static __inline__ GLKMatrix4 GLKMatrix4MakeTranslation(float tx, float ty, float tz); +static __inline__ GLKMatrix4 GLKMatrix4MakeScale(float sx, float sy, float sz); +static __inline__ GLKMatrix4 GLKMatrix4MakeRotation(float radians, float x, float y, float z); + +static __inline__ GLKMatrix4 GLKMatrix4MakeXRotation(float radians); +static __inline__ GLKMatrix4 GLKMatrix4MakeYRotation(float radians); +static __inline__ GLKMatrix4 GLKMatrix4MakeZRotation(float radians); + +/* + Equivalent to gluPerspective. + */ +static __inline__ GLKMatrix4 GLKMatrix4MakePerspective(float fovyRadians, float aspect, float nearZ, float farZ); + +/* + Equivalent to glFrustum. + */ +static __inline__ GLKMatrix4 GLKMatrix4MakeFrustum(float left, float right, + float bottom, float top, + float nearZ, float farZ); + +/* + Equivalent to glOrtho. + */ +static __inline__ GLKMatrix4 GLKMatrix4MakeOrtho(float left, float right, + float bottom, float top, + float nearZ, float farZ); + +/* + Equivalent to gluLookAt. + */ +static __inline__ GLKMatrix4 GLKMatrix4MakeLookAt(float eyeX, float eyeY, float eyeZ, + float centerX, float centerY, float centerZ, + float upX, float upY, float upZ); + +/* + Returns the upper left 3x3 portion of the 4x4 matrix. + */ +static __inline__ GLKMatrix3 GLKMatrix4GetMatrix3(GLKMatrix4 matrix); +/* + Returns the upper left 2x2 portion of the 4x4 matrix. + */ +static __inline__ GLKMatrix2 GLKMatrix4GetMatrix2(GLKMatrix4 matrix); + +/* + GLKMatrix4GetRow returns vectors for rows 0, 1, and 2 whose last component will be the translation value tx, ty, and tz, respectively. + Valid row values range from 0 to 3, inclusive. + */ +static __inline__ GLKVector4 GLKMatrix4GetRow(GLKMatrix4 matrix, int row); +/* + GLKMatrix4GetColumn returns a vector for column 3 whose first three components will be the translation values tx, ty, and tz. + Valid column values range from 0 to 3, inclusive. + */ +static __inline__ GLKVector4 GLKMatrix4GetColumn(GLKMatrix4 matrix, int column); + +/* + GLKMatrix4SetRow expects that the vector for row 0, 1, and 2 will have a translation value as its last component. + Valid row values range from 0 to 3, inclusive. + */ +static __inline__ GLKMatrix4 GLKMatrix4SetRow(GLKMatrix4 matrix, int row, GLKVector4 vector); +/* + GLKMatrix4SetColumn expects that the vector for column 3 will contain the translation values tx, ty, and tz as its first three components, respectively. + Valid column values range from 0 to 3, inclusive. + */ +static __inline__ GLKMatrix4 GLKMatrix4SetColumn(GLKMatrix4 matrix, int column, GLKVector4 vector); + +static __inline__ GLKMatrix4 GLKMatrix4Transpose(GLKMatrix4 matrix); + +GLKMatrix4 GLKMatrix4Invert(GLKMatrix4 matrix, bool *isInvertible); +GLKMatrix4 GLKMatrix4InvertAndTranspose(GLKMatrix4 matrix, bool *isInvertible); + +static __inline__ GLKMatrix4 GLKMatrix4Multiply(GLKMatrix4 matrixLeft, GLKMatrix4 matrixRight); + +static __inline__ GLKMatrix4 GLKMatrix4Add(GLKMatrix4 matrixLeft, GLKMatrix4 matrixRight); +static __inline__ GLKMatrix4 GLKMatrix4Subtract(GLKMatrix4 matrixLeft, GLKMatrix4 matrixRight); + +static __inline__ GLKMatrix4 GLKMatrix4Translate(GLKMatrix4 matrix, float tx, float ty, float tz); +static __inline__ GLKMatrix4 GLKMatrix4TranslateWithVector3(GLKMatrix4 matrix, GLKVector3 translationVector); +/* + The last component of the GLKVector4, translationVector, is ignored. + */ +static __inline__ GLKMatrix4 GLKMatrix4TranslateWithVector4(GLKMatrix4 matrix, GLKVector4 translationVector); + +static __inline__ GLKMatrix4 GLKMatrix4Scale(GLKMatrix4 matrix, float sx, float sy, float sz); +static __inline__ GLKMatrix4 GLKMatrix4ScaleWithVector3(GLKMatrix4 matrix, GLKVector3 scaleVector); +/* + The last component of the GLKVector4, scaleVector, is ignored. + */ +static __inline__ GLKMatrix4 GLKMatrix4ScaleWithVector4(GLKMatrix4 matrix, GLKVector4 scaleVector); + +static __inline__ GLKMatrix4 GLKMatrix4Rotate(GLKMatrix4 matrix, float radians, float x, float y, float z); +static __inline__ GLKMatrix4 GLKMatrix4RotateWithVector3(GLKMatrix4 matrix, float radians, GLKVector3 axisVector); +/* + The last component of the GLKVector4, axisVector, is ignored. + */ +static __inline__ GLKMatrix4 GLKMatrix4RotateWithVector4(GLKMatrix4 matrix, float radians, GLKVector4 axisVector); + +static __inline__ GLKMatrix4 GLKMatrix4RotateX(GLKMatrix4 matrix, float radians); +static __inline__ GLKMatrix4 GLKMatrix4RotateY(GLKMatrix4 matrix, float radians); +static __inline__ GLKMatrix4 GLKMatrix4RotateZ(GLKMatrix4 matrix, float radians); + +/* + Assumes 0 in the w component. + */ +static __inline__ GLKVector3 GLKMatrix4MultiplyVector3(GLKMatrix4 matrixLeft, GLKVector3 vectorRight); +/* + Assumes 1 in the w component. + */ +static __inline__ GLKVector3 GLKMatrix4MultiplyVector3WithTranslation(GLKMatrix4 matrixLeft, GLKVector3 vectorRight); +/* + Assumes 1 in the w component and divides the resulting vector by w before returning. + */ +static __inline__ GLKVector3 GLKMatrix4MultiplyAndProjectVector3(GLKMatrix4 matrixLeft, GLKVector3 vectorRight); + +/* + Assumes 0 in the w component. + */ +static __inline__ void GLKMatrix4MultiplyVector3Array(GLKMatrix4 matrix, GLKVector3 *vectors, size_t vectorCount); +/* + Assumes 1 in the w component. + */ +static __inline__ void GLKMatrix4MultiplyVector3ArrayWithTranslation(GLKMatrix4 matrix, GLKVector3 *vectors, size_t vectorCount); +/* + Assumes 1 in the w component and divides the resulting vector by w before returning. + */ +static __inline__ void GLKMatrix4MultiplyAndProjectVector3Array(GLKMatrix4 matrix, GLKVector3 *vectors, size_t vectorCount); + +static __inline__ GLKVector4 GLKMatrix4MultiplyVector4(GLKMatrix4 matrixLeft, GLKVector4 vectorRight); + +static __inline__ void GLKMatrix4MultiplyVector4Array(GLKMatrix4 matrix, GLKVector4 *vectors, size_t vectorCount); + +#pragma mark - +#pragma mark Implementations +#pragma mark - + +static __inline__ GLKMatrix4 GLKMatrix4Make(float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33) +{ + GLKMatrix4 m = { m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33 }; + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeAndTranspose(float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33) +{ + GLKMatrix4 m = { m00, m10, m20, m30, + m01, m11, m21, m31, + m02, m12, m22, m32, + m03, m13, m23, m33 }; + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeWithArray(float values[16]) +{ + GLKMatrix4 m = { values[0], values[1], values[2], values[3], + values[4], values[5], values[6], values[7], + values[8], values[9], values[10], values[11], + values[12], values[13], values[14], values[15] }; + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeWithArrayAndTranspose(float values[16]) +{ +#if defined(__ARM_NEON__) + float32x4x4_t m = vld4q_f32(values); + return *(GLKMatrix4 *)&m; +#else + GLKMatrix4 m = { values[0], values[4], values[8], values[12], + values[1], values[5], values[9], values[13], + values[2], values[6], values[10], values[14], + values[3], values[7], values[11], values[15] }; + return m; +#endif +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeWithRows(GLKVector4 row0, + GLKVector4 row1, + GLKVector4 row2, + GLKVector4 row3) +{ + GLKMatrix4 m = { row0.v[0], row1.v[0], row2.v[0], row3.v[0], + row0.v[1], row1.v[1], row2.v[1], row3.v[1], + row0.v[2], row1.v[2], row2.v[2], row3.v[2], + row0.v[3], row1.v[3], row2.v[3], row3.v[3] }; + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeWithColumns(GLKVector4 column0, + GLKVector4 column1, + GLKVector4 column2, + GLKVector4 column3) +{ +#if defined(__ARM_NEON__) + float32x4x4_t m; + m.val[0] = vld1q_f32(column0.v); + m.val[1] = vld1q_f32(column1.v); + m.val[2] = vld1q_f32(column2.v); + m.val[3] = vld1q_f32(column3.v); + return *(GLKMatrix4 *)&m; +#else + GLKMatrix4 m = { column0.v[0], column0.v[1], column0.v[2], column0.v[3], + column1.v[0], column1.v[1], column1.v[2], column1.v[3], + column2.v[0], column2.v[1], column2.v[2], column2.v[3], + column3.v[0], column3.v[1], column3.v[2], column3.v[3] }; + return m; +#endif +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeWithQuaternion(GLKQuaternion quaternion) +{ + quaternion = GLKQuaternionNormalize(quaternion); + + float x = quaternion.q[0]; + float y = quaternion.q[1]; + float z = quaternion.q[2]; + float w = quaternion.q[3]; + + float _2x = x + x; + float _2y = y + y; + float _2z = z + z; + float _2w = w + w; + + GLKMatrix4 m = { 1.0f - _2y * y - _2z * z, + _2x * y + _2w * z, + _2x * z - _2w * y, + 0.0f, + _2x * y - _2w * z, + 1.0f - _2x * x - _2z * z, + _2y * z + _2w * x, + 0.0f, + _2x * z + _2w * y, + _2y * z - _2w * x, + 1.0f - _2x * x - _2y * y, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f }; + + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeTranslation(float tx, float ty, float tz) +{ + GLKMatrix4 m = GLKMatrix4Identity; + m.m[12] = tx; + m.m[13] = ty; + m.m[14] = tz; + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeScale(float sx, float sy, float sz) +{ + GLKMatrix4 m = GLKMatrix4Identity; + m.m[0] = sx; + m.m[5] = sy; + m.m[10] = sz; + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeRotation(float radians, float x, float y, float z) +{ + GLKVector3 v = GLKVector3Normalize(GLKVector3Make(x, y, z)); + float cos = cosf(radians); + float cosp = 1.0f - cos; + float sin = sinf(radians); + + GLKMatrix4 m = { cos + cosp * v.v[0] * v.v[0], + cosp * v.v[0] * v.v[1] + v.v[2] * sin, + cosp * v.v[0] * v.v[2] - v.v[1] * sin, + 0.0f, + cosp * v.v[0] * v.v[1] - v.v[2] * sin, + cos + cosp * v.v[1] * v.v[1], + cosp * v.v[1] * v.v[2] + v.v[0] * sin, + 0.0f, + cosp * v.v[0] * v.v[2] + v.v[1] * sin, + cosp * v.v[1] * v.v[2] - v.v[0] * sin, + cos + cosp * v.v[2] * v.v[2], + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f }; + + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeXRotation(float radians) +{ + float cos = cosf(radians); + float sin = sinf(radians); + + GLKMatrix4 m = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, cos, sin, 0.0f, + 0.0f, -sin, cos, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; + + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeYRotation(float radians) +{ + float cos = cosf(radians); + float sin = sinf(radians); + + GLKMatrix4 m = { cos, 0.0f, -sin, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + sin, 0.0f, cos, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; + + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeZRotation(float radians) +{ + float cos = cosf(radians); + float sin = sinf(radians); + + GLKMatrix4 m = { cos, sin, 0.0f, 0.0f, + -sin, cos, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; + + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakePerspective(float fovyRadians, float aspect, float nearZ, float farZ) +{ + float cotan = 1.0f / tanf(fovyRadians / 2.0f); + + GLKMatrix4 m = { cotan / aspect, 0.0f, 0.0f, 0.0f, + 0.0f, cotan, 0.0f, 0.0f, + 0.0f, 0.0f, (farZ + nearZ) / (nearZ - farZ), -1.0f, + 0.0f, 0.0f, (2.0f * farZ * nearZ) / (nearZ - farZ), 0.0f }; + + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeFrustum(float left, float right, + float bottom, float top, + float nearZ, float farZ) +{ + float ral = right + left; + float rsl = right - left; + float tsb = top - bottom; + float tab = top + bottom; + float fan = farZ + nearZ; + float fsn = farZ - nearZ; + + GLKMatrix4 m = { 2.0f * nearZ / rsl, 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f * nearZ / tsb, 0.0f, 0.0f, + ral / rsl, tab / tsb, -fan / fsn, -1.0f, + 0.0f, 0.0f, (-2.0f * farZ * nearZ) / fsn, 0.0f }; + + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeOrtho(float left, float right, + float bottom, float top, + float nearZ, float farZ) +{ + float ral = right + left; + float rsl = right - left; + float tab = top + bottom; + float tsb = top - bottom; + float fan = farZ + nearZ; + float fsn = farZ - nearZ; + + GLKMatrix4 m = { 2.0f / rsl, 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f / tsb, 0.0f, 0.0f, + 0.0f, 0.0f, -2.0f / fsn, 0.0f, + -ral / rsl, -tab / tsb, -fan / fsn, 1.0f }; + + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4MakeLookAt(float eyeX, float eyeY, float eyeZ, + float centerX, float centerY, float centerZ, + float upX, float upY, float upZ) +{ + GLKVector3 ev = { eyeX, eyeY, eyeZ }; + GLKVector3 cv = { centerX, centerY, centerZ }; + GLKVector3 uv = { upX, upY, upZ }; + GLKVector3 n = GLKVector3Normalize(GLKVector3Add(ev, GLKVector3Negate(cv))); + GLKVector3 u = GLKVector3Normalize(GLKVector3CrossProduct(uv, n)); + GLKVector3 v = GLKVector3CrossProduct(n, u); + + GLKMatrix4 m = { u.v[0], v.v[0], n.v[0], 0.0f, + u.v[1], v.v[1], n.v[1], 0.0f, + u.v[2], v.v[2], n.v[2], 0.0f, + GLKVector3DotProduct(GLKVector3Negate(u), ev), + GLKVector3DotProduct(GLKVector3Negate(v), ev), + GLKVector3DotProduct(GLKVector3Negate(n), ev), + 1.0f }; + + return m; +} + +static __inline__ GLKMatrix3 GLKMatrix4GetMatrix3(GLKMatrix4 matrix) +{ + GLKMatrix3 m = { matrix.m[0], matrix.m[1], matrix.m[2], + matrix.m[4], matrix.m[5], matrix.m[6], + matrix.m[8], matrix.m[9], matrix.m[10] }; + return m; +} + +static __inline__ GLKMatrix2 GLKMatrix4GetMatrix2(GLKMatrix4 matrix) +{ + GLKMatrix2 m = { matrix.m[0], matrix.m[1], + matrix.m[4], matrix.m[5] }; + return m; +} + +static __inline__ GLKVector4 GLKMatrix4GetRow(GLKMatrix4 matrix, int row) +{ + GLKVector4 v = { matrix.m[row], matrix.m[4 + row], matrix.m[8 + row], matrix.m[12 + row] }; + return v; +} + +static __inline__ GLKVector4 GLKMatrix4GetColumn(GLKMatrix4 matrix, int column) +{ +#if defined(__ARM_NEON__) + float32x4_t v = vld1q_f32(&(matrix.m[column * 4])); + return *(GLKVector4 *)&v; +#else + GLKVector4 v = { matrix.m[column * 4 + 0], matrix.m[column * 4 + 1], matrix.m[column * 4 + 2], matrix.m[column * 4 + 3] }; + return v; +#endif +} + +static __inline__ GLKMatrix4 GLKMatrix4SetRow(GLKMatrix4 matrix, int row, GLKVector4 vector) +{ + matrix.m[row] = vector.v[0]; + matrix.m[row + 4] = vector.v[1]; + matrix.m[row + 8] = vector.v[2]; + matrix.m[row + 12] = vector.v[3]; + + return matrix; +} + +static __inline__ GLKMatrix4 GLKMatrix4SetColumn(GLKMatrix4 matrix, int column, GLKVector4 vector) +{ +#if defined(__ARM_NEON__) + float *dst = &(matrix.m[column * 4]); + vst1q_f32(dst, vld1q_f32(vector.v)); + return matrix; +#else + matrix.m[column * 4 + 0] = vector.v[0]; + matrix.m[column * 4 + 1] = vector.v[1]; + matrix.m[column * 4 + 2] = vector.v[2]; + matrix.m[column * 4 + 3] = vector.v[3]; + + return matrix; +#endif +} + +static __inline__ GLKMatrix4 GLKMatrix4Transpose(GLKMatrix4 matrix) +{ +#if defined(__ARM_NEON__) + float32x4x4_t m = vld4q_f32(matrix.m); + return *(GLKMatrix4 *)&m; +#else + GLKMatrix4 m = { matrix.m[0], matrix.m[4], matrix.m[8], matrix.m[12], + matrix.m[1], matrix.m[5], matrix.m[9], matrix.m[13], + matrix.m[2], matrix.m[6], matrix.m[10], matrix.m[14], + matrix.m[3], matrix.m[7], matrix.m[11], matrix.m[15] }; + return m; +#endif +} + +static __inline__ GLKMatrix4 GLKMatrix4Multiply(GLKMatrix4 matrixLeft, GLKMatrix4 matrixRight) +{ +#if defined(__ARM_NEON__) + float32x4x4_t iMatrixLeft = *(float32x4x4_t *)&matrixLeft; + float32x4x4_t iMatrixRight = *(float32x4x4_t *)&matrixRight; + float32x4x4_t m; + + m.val[0] = vmulq_n_f32(iMatrixLeft.val[0], vgetq_lane_f32(iMatrixRight.val[0], 0)); + m.val[1] = vmulq_n_f32(iMatrixLeft.val[0], vgetq_lane_f32(iMatrixRight.val[1], 0)); + m.val[2] = vmulq_n_f32(iMatrixLeft.val[0], vgetq_lane_f32(iMatrixRight.val[2], 0)); + m.val[3] = vmulq_n_f32(iMatrixLeft.val[0], vgetq_lane_f32(iMatrixRight.val[3], 0)); + + m.val[0] = vmlaq_n_f32(m.val[0], iMatrixLeft.val[1], vgetq_lane_f32(iMatrixRight.val[0], 1)); + m.val[1] = vmlaq_n_f32(m.val[1], iMatrixLeft.val[1], vgetq_lane_f32(iMatrixRight.val[1], 1)); + m.val[2] = vmlaq_n_f32(m.val[2], iMatrixLeft.val[1], vgetq_lane_f32(iMatrixRight.val[2], 1)); + m.val[3] = vmlaq_n_f32(m.val[3], iMatrixLeft.val[1], vgetq_lane_f32(iMatrixRight.val[3], 1)); + + m.val[0] = vmlaq_n_f32(m.val[0], iMatrixLeft.val[2], vgetq_lane_f32(iMatrixRight.val[0], 2)); + m.val[1] = vmlaq_n_f32(m.val[1], iMatrixLeft.val[2], vgetq_lane_f32(iMatrixRight.val[1], 2)); + m.val[2] = vmlaq_n_f32(m.val[2], iMatrixLeft.val[2], vgetq_lane_f32(iMatrixRight.val[2], 2)); + m.val[3] = vmlaq_n_f32(m.val[3], iMatrixLeft.val[2], vgetq_lane_f32(iMatrixRight.val[3], 2)); + + m.val[0] = vmlaq_n_f32(m.val[0], iMatrixLeft.val[3], vgetq_lane_f32(iMatrixRight.val[0], 3)); + m.val[1] = vmlaq_n_f32(m.val[1], iMatrixLeft.val[3], vgetq_lane_f32(iMatrixRight.val[1], 3)); + m.val[2] = vmlaq_n_f32(m.val[2], iMatrixLeft.val[3], vgetq_lane_f32(iMatrixRight.val[2], 3)); + m.val[3] = vmlaq_n_f32(m.val[3], iMatrixLeft.val[3], vgetq_lane_f32(iMatrixRight.val[3], 3)); + + return *(GLKMatrix4 *)&m; +#else + GLKMatrix4 m; + + m.m[0] = matrixLeft.m[0] * matrixRight.m[0] + matrixLeft.m[4] * matrixRight.m[1] + matrixLeft.m[8] * matrixRight.m[2] + matrixLeft.m[12] * matrixRight.m[3]; + m.m[4] = matrixLeft.m[0] * matrixRight.m[4] + matrixLeft.m[4] * matrixRight.m[5] + matrixLeft.m[8] * matrixRight.m[6] + matrixLeft.m[12] * matrixRight.m[7]; + m.m[8] = matrixLeft.m[0] * matrixRight.m[8] + matrixLeft.m[4] * matrixRight.m[9] + matrixLeft.m[8] * matrixRight.m[10] + matrixLeft.m[12] * matrixRight.m[11]; + m.m[12] = matrixLeft.m[0] * matrixRight.m[12] + matrixLeft.m[4] * matrixRight.m[13] + matrixLeft.m[8] * matrixRight.m[14] + matrixLeft.m[12] * matrixRight.m[15]; + + m.m[1] = matrixLeft.m[1] * matrixRight.m[0] + matrixLeft.m[5] * matrixRight.m[1] + matrixLeft.m[9] * matrixRight.m[2] + matrixLeft.m[13] * matrixRight.m[3]; + m.m[5] = matrixLeft.m[1] * matrixRight.m[4] + matrixLeft.m[5] * matrixRight.m[5] + matrixLeft.m[9] * matrixRight.m[6] + matrixLeft.m[13] * matrixRight.m[7]; + m.m[9] = matrixLeft.m[1] * matrixRight.m[8] + matrixLeft.m[5] * matrixRight.m[9] + matrixLeft.m[9] * matrixRight.m[10] + matrixLeft.m[13] * matrixRight.m[11]; + m.m[13] = matrixLeft.m[1] * matrixRight.m[12] + matrixLeft.m[5] * matrixRight.m[13] + matrixLeft.m[9] * matrixRight.m[14] + matrixLeft.m[13] * matrixRight.m[15]; + + m.m[2] = matrixLeft.m[2] * matrixRight.m[0] + matrixLeft.m[6] * matrixRight.m[1] + matrixLeft.m[10] * matrixRight.m[2] + matrixLeft.m[14] * matrixRight.m[3]; + m.m[6] = matrixLeft.m[2] * matrixRight.m[4] + matrixLeft.m[6] * matrixRight.m[5] + matrixLeft.m[10] * matrixRight.m[6] + matrixLeft.m[14] * matrixRight.m[7]; + m.m[10] = matrixLeft.m[2] * matrixRight.m[8] + matrixLeft.m[6] * matrixRight.m[9] + matrixLeft.m[10] * matrixRight.m[10] + matrixLeft.m[14] * matrixRight.m[11]; + m.m[14] = matrixLeft.m[2] * matrixRight.m[12] + matrixLeft.m[6] * matrixRight.m[13] + matrixLeft.m[10] * matrixRight.m[14] + matrixLeft.m[14] * matrixRight.m[15]; + + m.m[3] = matrixLeft.m[3] * matrixRight.m[0] + matrixLeft.m[7] * matrixRight.m[1] + matrixLeft.m[11] * matrixRight.m[2] + matrixLeft.m[15] * matrixRight.m[3]; + m.m[7] = matrixLeft.m[3] * matrixRight.m[4] + matrixLeft.m[7] * matrixRight.m[5] + matrixLeft.m[11] * matrixRight.m[6] + matrixLeft.m[15] * matrixRight.m[7]; + m.m[11] = matrixLeft.m[3] * matrixRight.m[8] + matrixLeft.m[7] * matrixRight.m[9] + matrixLeft.m[11] * matrixRight.m[10] + matrixLeft.m[15] * matrixRight.m[11]; + m.m[15] = matrixLeft.m[3] * matrixRight.m[12] + matrixLeft.m[7] * matrixRight.m[13] + matrixLeft.m[11] * matrixRight.m[14] + matrixLeft.m[15] * matrixRight.m[15]; + + return m; +#endif +} + +static __inline__ GLKMatrix4 GLKMatrix4Add(GLKMatrix4 matrixLeft, GLKMatrix4 matrixRight) +{ +#if defined(__ARM_NEON__) + float32x4x4_t iMatrixLeft = *(float32x4x4_t *)&matrixLeft; + float32x4x4_t iMatrixRight = *(float32x4x4_t *)&matrixRight; + float32x4x4_t m; + + m.val[0] = vaddq_f32(iMatrixLeft.val[0], iMatrixRight.val[0]); + m.val[1] = vaddq_f32(iMatrixLeft.val[1], iMatrixRight.val[1]); + m.val[2] = vaddq_f32(iMatrixLeft.val[2], iMatrixRight.val[2]); + m.val[3] = vaddq_f32(iMatrixLeft.val[3], iMatrixRight.val[3]); + + return *(GLKMatrix4 *)&m; +#else + GLKMatrix4 m; + + m.m[0] = matrixLeft.m[0] + matrixRight.m[0]; + m.m[1] = matrixLeft.m[1] + matrixRight.m[1]; + m.m[2] = matrixLeft.m[2] + matrixRight.m[2]; + m.m[3] = matrixLeft.m[3] + matrixRight.m[3]; + + m.m[4] = matrixLeft.m[4] + matrixRight.m[4]; + m.m[5] = matrixLeft.m[5] + matrixRight.m[5]; + m.m[6] = matrixLeft.m[6] + matrixRight.m[6]; + m.m[7] = matrixLeft.m[7] + matrixRight.m[7]; + + m.m[8] = matrixLeft.m[8] + matrixRight.m[8]; + m.m[9] = matrixLeft.m[9] + matrixRight.m[9]; + m.m[10] = matrixLeft.m[10] + matrixRight.m[10]; + m.m[11] = matrixLeft.m[11] + matrixRight.m[11]; + + m.m[12] = matrixLeft.m[12] + matrixRight.m[12]; + m.m[13] = matrixLeft.m[13] + matrixRight.m[13]; + m.m[14] = matrixLeft.m[14] + matrixRight.m[14]; + m.m[15] = matrixLeft.m[15] + matrixRight.m[15]; + + return m; +#endif +} + +static __inline__ GLKMatrix4 GLKMatrix4Subtract(GLKMatrix4 matrixLeft, GLKMatrix4 matrixRight) +{ +#if defined(__ARM_NEON__) + float32x4x4_t iMatrixLeft = *(float32x4x4_t *)&matrixLeft; + float32x4x4_t iMatrixRight = *(float32x4x4_t *)&matrixRight; + float32x4x4_t m; + + m.val[0] = vsubq_f32(iMatrixLeft.val[0], iMatrixRight.val[0]); + m.val[1] = vsubq_f32(iMatrixLeft.val[1], iMatrixRight.val[1]); + m.val[2] = vsubq_f32(iMatrixLeft.val[2], iMatrixRight.val[2]); + m.val[3] = vsubq_f32(iMatrixLeft.val[3], iMatrixRight.val[3]); + + return *(GLKMatrix4 *)&m; +#else + GLKMatrix4 m; + + m.m[0] = matrixLeft.m[0] - matrixRight.m[0]; + m.m[1] = matrixLeft.m[1] - matrixRight.m[1]; + m.m[2] = matrixLeft.m[2] - matrixRight.m[2]; + m.m[3] = matrixLeft.m[3] - matrixRight.m[3]; + + m.m[4] = matrixLeft.m[4] - matrixRight.m[4]; + m.m[5] = matrixLeft.m[5] - matrixRight.m[5]; + m.m[6] = matrixLeft.m[6] - matrixRight.m[6]; + m.m[7] = matrixLeft.m[7] - matrixRight.m[7]; + + m.m[8] = matrixLeft.m[8] - matrixRight.m[8]; + m.m[9] = matrixLeft.m[9] - matrixRight.m[9]; + m.m[10] = matrixLeft.m[10] - matrixRight.m[10]; + m.m[11] = matrixLeft.m[11] - matrixRight.m[11]; + + m.m[12] = matrixLeft.m[12] - matrixRight.m[12]; + m.m[13] = matrixLeft.m[13] - matrixRight.m[13]; + m.m[14] = matrixLeft.m[14] - matrixRight.m[14]; + m.m[15] = matrixLeft.m[15] - matrixRight.m[15]; + + return m; +#endif +} + +static __inline__ GLKMatrix4 GLKMatrix4Translate(GLKMatrix4 matrix, float tx, float ty, float tz) +{ + GLKMatrix4 m = { matrix.m[0], matrix.m[1], matrix.m[2], matrix.m[3], + matrix.m[4], matrix.m[5], matrix.m[6], matrix.m[7], + matrix.m[8], matrix.m[9], matrix.m[10], matrix.m[11], + matrix.m[0] * tx + matrix.m[4] * ty + matrix.m[8] * tz + matrix.m[12], + matrix.m[1] * tx + matrix.m[5] * ty + matrix.m[9] * tz + matrix.m[13], + matrix.m[2] * tx + matrix.m[6] * ty + matrix.m[10] * tz + matrix.m[14], + matrix.m[15] }; + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4TranslateWithVector3(GLKMatrix4 matrix, GLKVector3 translationVector) +{ + GLKMatrix4 m = { matrix.m[0], matrix.m[1], matrix.m[2], matrix.m[3], + matrix.m[4], matrix.m[5], matrix.m[6], matrix.m[7], + matrix.m[8], matrix.m[9], matrix.m[10], matrix.m[11], + matrix.m[0] * translationVector.v[0] + matrix.m[4] * translationVector.v[1] + matrix.m[8] * translationVector.v[2] + matrix.m[12], + matrix.m[1] * translationVector.v[0] + matrix.m[5] * translationVector.v[1] + matrix.m[9] * translationVector.v[2] + matrix.m[13], + matrix.m[2] * translationVector.v[0] + matrix.m[6] * translationVector.v[1] + matrix.m[10] * translationVector.v[2] + matrix.m[14], + matrix.m[15] }; + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4TranslateWithVector4(GLKMatrix4 matrix, GLKVector4 translationVector) +{ + GLKMatrix4 m = { matrix.m[0], matrix.m[1], matrix.m[2], matrix.m[3], + matrix.m[4], matrix.m[5], matrix.m[6], matrix.m[7], + matrix.m[8], matrix.m[9], matrix.m[10], matrix.m[11], + matrix.m[0] * translationVector.v[0] + matrix.m[4] * translationVector.v[1] + matrix.m[8] * translationVector.v[2] + matrix.m[12], + matrix.m[1] * translationVector.v[0] + matrix.m[5] * translationVector.v[1] + matrix.m[9] * translationVector.v[2] + matrix.m[13], + matrix.m[2] * translationVector.v[0] + matrix.m[6] * translationVector.v[1] + matrix.m[10] * translationVector.v[2] + matrix.m[14], + matrix.m[15] }; + return m; +} + +static __inline__ GLKMatrix4 GLKMatrix4Scale(GLKMatrix4 matrix, float sx, float sy, float sz) +{ +#if defined(__ARM_NEON__) + float32x4x4_t iMatrix = *(float32x4x4_t *)&matrix; + float32x4x4_t m; + + m.val[0] = vmulq_n_f32(iMatrix.val[0], (float32_t)sx); + m.val[1] = vmulq_n_f32(iMatrix.val[1], (float32_t)sy); + m.val[2] = vmulq_n_f32(iMatrix.val[2], (float32_t)sz); + m.val[3] = iMatrix.val[3]; + + return *(GLKMatrix4 *)&m; +#else + GLKMatrix4 m = { matrix.m[0] * sx, matrix.m[1] * sx, matrix.m[2] * sx, matrix.m[3] * sx, + matrix.m[4] * sy, matrix.m[5] * sy, matrix.m[6] * sy, matrix.m[7] * sy, + matrix.m[8] * sz, matrix.m[9] * sz, matrix.m[10] * sz, matrix.m[11] * sz, + matrix.m[12], matrix.m[13], matrix.m[14], matrix.m[15] }; + return m; +#endif +} + +static __inline__ GLKMatrix4 GLKMatrix4ScaleWithVector3(GLKMatrix4 matrix, GLKVector3 scaleVector) +{ +#if defined(__ARM_NEON__) + float32x4x4_t iMatrix = *(float32x4x4_t *)&matrix; + float32x4x4_t m; + + m.val[0] = vmulq_n_f32(iMatrix.val[0], (float32_t)scaleVector.v[0]); + m.val[1] = vmulq_n_f32(iMatrix.val[1], (float32_t)scaleVector.v[1]); + m.val[2] = vmulq_n_f32(iMatrix.val[2], (float32_t)scaleVector.v[2]); + m.val[3] = iMatrix.val[3]; + + return *(GLKMatrix4 *)&m; +#else + GLKMatrix4 m = { matrix.m[0] * scaleVector.v[0], matrix.m[1] * scaleVector.v[0], matrix.m[2] * scaleVector.v[0], matrix.m[3] * scaleVector.v[0], + matrix.m[4] * scaleVector.v[1], matrix.m[5] * scaleVector.v[1], matrix.m[6] * scaleVector.v[1], matrix.m[7] * scaleVector.v[1], + matrix.m[8] * scaleVector.v[2], matrix.m[9] * scaleVector.v[2], matrix.m[10] * scaleVector.v[2], matrix.m[11] * scaleVector.v[2], + matrix.m[12], matrix.m[13], matrix.m[14], matrix.m[15] }; + return m; +#endif +} + +static __inline__ GLKMatrix4 GLKMatrix4ScaleWithVector4(GLKMatrix4 matrix, GLKVector4 scaleVector) +{ +#if defined(__ARM_NEON__) + float32x4x4_t iMatrix = *(float32x4x4_t *)&matrix; + float32x4x4_t m; + + m.val[0] = vmulq_n_f32(iMatrix.val[0], (float32_t)scaleVector.v[0]); + m.val[1] = vmulq_n_f32(iMatrix.val[1], (float32_t)scaleVector.v[1]); + m.val[2] = vmulq_n_f32(iMatrix.val[2], (float32_t)scaleVector.v[2]); + m.val[3] = iMatrix.val[3]; + + return *(GLKMatrix4 *)&m; +#else + GLKMatrix4 m = { matrix.m[0] * scaleVector.v[0], matrix.m[1] * scaleVector.v[0], matrix.m[2] * scaleVector.v[0], matrix.m[3] * scaleVector.v[0], + matrix.m[4] * scaleVector.v[1], matrix.m[5] * scaleVector.v[1], matrix.m[6] * scaleVector.v[1], matrix.m[7] * scaleVector.v[1], + matrix.m[8] * scaleVector.v[2], matrix.m[9] * scaleVector.v[2], matrix.m[10] * scaleVector.v[2], matrix.m[11] * scaleVector.v[2], + matrix.m[12], matrix.m[13], matrix.m[14], matrix.m[15] }; + return m; +#endif +} + +static __inline__ GLKMatrix4 GLKMatrix4Rotate(GLKMatrix4 matrix, float radians, float x, float y, float z) +{ + GLKMatrix4 rm = GLKMatrix4MakeRotation(radians, x, y, z); + return GLKMatrix4Multiply(matrix, rm); +} + +static __inline__ GLKMatrix4 GLKMatrix4RotateWithVector3(GLKMatrix4 matrix, float radians, GLKVector3 axisVector) +{ + GLKMatrix4 rm = GLKMatrix4MakeRotation(radians, axisVector.v[0], axisVector.v[1], axisVector.v[2]); + return GLKMatrix4Multiply(matrix, rm); +} + +static __inline__ GLKMatrix4 GLKMatrix4RotateWithVector4(GLKMatrix4 matrix, float radians, GLKVector4 axisVector) +{ + GLKMatrix4 rm = GLKMatrix4MakeRotation(radians, axisVector.v[0], axisVector.v[1], axisVector.v[2]); + return GLKMatrix4Multiply(matrix, rm); +} + +static __inline__ GLKMatrix4 GLKMatrix4RotateX(GLKMatrix4 matrix, float radians) +{ + GLKMatrix4 rm = GLKMatrix4MakeXRotation(radians); + return GLKMatrix4Multiply(matrix, rm); +} + +static __inline__ GLKMatrix4 GLKMatrix4RotateY(GLKMatrix4 matrix, float radians) +{ + GLKMatrix4 rm = GLKMatrix4MakeYRotation(radians); + return GLKMatrix4Multiply(matrix, rm); +} + +static __inline__ GLKMatrix4 GLKMatrix4RotateZ(GLKMatrix4 matrix, float radians) +{ + GLKMatrix4 rm = GLKMatrix4MakeZRotation(radians); + return GLKMatrix4Multiply(matrix, rm); +} + +static __inline__ GLKVector3 GLKMatrix4MultiplyVector3(GLKMatrix4 matrixLeft, GLKVector3 vectorRight) +{ + GLKVector4 v4 = GLKMatrix4MultiplyVector4(matrixLeft, GLKVector4Make(vectorRight.v[0], vectorRight.v[1], vectorRight.v[2], 0.0f)); + return GLKVector3Make(v4.v[0], v4.v[1], v4.v[2]); +} + +static __inline__ GLKVector3 GLKMatrix4MultiplyVector3WithTranslation(GLKMatrix4 matrixLeft, GLKVector3 vectorRight) +{ + GLKVector4 v4 = GLKMatrix4MultiplyVector4(matrixLeft, GLKVector4Make(vectorRight.v[0], vectorRight.v[1], vectorRight.v[2], 1.0f)); + return GLKVector3Make(v4.v[0], v4.v[1], v4.v[2]); +} + +static __inline__ GLKVector3 GLKMatrix4MultiplyAndProjectVector3(GLKMatrix4 matrixLeft, GLKVector3 vectorRight) +{ + GLKVector4 v4 = GLKMatrix4MultiplyVector4(matrixLeft, GLKVector4Make(vectorRight.v[0], vectorRight.v[1], vectorRight.v[2], 1.0f)); + return GLKVector3MultiplyScalar(GLKVector3Make(v4.v[0], v4.v[1], v4.v[2]), 1.0f / v4.v[3]); +} + +static __inline__ void GLKMatrix4MultiplyVector3Array(GLKMatrix4 matrix, GLKVector3 *vectors, size_t vectorCount) +{ + size_t i; + for (i=0; i < vectorCount; i++) + vectors[i] = GLKMatrix4MultiplyVector3(matrix, vectors[i]); +} + +static __inline__ void GLKMatrix4MultiplyVector3ArrayWithTranslation(GLKMatrix4 matrix, GLKVector3 *vectors, size_t vectorCount) +{ + size_t i; + for (i=0; i < vectorCount; i++) + vectors[i] = GLKMatrix4MultiplyVector3WithTranslation(matrix, vectors[i]); +} + +static __inline__ void GLKMatrix4MultiplyAndProjectVector3Array(GLKMatrix4 matrix, GLKVector3 *vectors, size_t vectorCount) +{ + size_t i; + for (i=0; i < vectorCount; i++) + vectors[i] = GLKMatrix4MultiplyAndProjectVector3(matrix, vectors[i]); +} + +static __inline__ GLKVector4 GLKMatrix4MultiplyVector4(GLKMatrix4 matrixLeft, GLKVector4 vectorRight) +{ +#if defined(__ARM_NEON__) + float32x4x4_t iMatrix = *(float32x4x4_t *)&matrixLeft; + float32x4_t v; + + iMatrix.val[0] = vmulq_n_f32(iMatrix.val[0], (float32_t)vectorRight.v[0]); + iMatrix.val[1] = vmulq_n_f32(iMatrix.val[1], (float32_t)vectorRight.v[1]); + iMatrix.val[2] = vmulq_n_f32(iMatrix.val[2], (float32_t)vectorRight.v[2]); + iMatrix.val[3] = vmulq_n_f32(iMatrix.val[3], (float32_t)vectorRight.v[3]); + + iMatrix.val[0] = vaddq_f32(iMatrix.val[0], iMatrix.val[1]); + iMatrix.val[2] = vaddq_f32(iMatrix.val[2], iMatrix.val[3]); + + v = vaddq_f32(iMatrix.val[0], iMatrix.val[2]); + + return *(GLKVector4 *)&v; +#else + GLKVector4 v = { matrixLeft.m[0] * vectorRight.v[0] + matrixLeft.m[4] * vectorRight.v[1] + matrixLeft.m[8] * vectorRight.v[2] + matrixLeft.m[12] * vectorRight.v[3], + matrixLeft.m[1] * vectorRight.v[0] + matrixLeft.m[5] * vectorRight.v[1] + matrixLeft.m[9] * vectorRight.v[2] + matrixLeft.m[13] * vectorRight.v[3], + matrixLeft.m[2] * vectorRight.v[0] + matrixLeft.m[6] * vectorRight.v[1] + matrixLeft.m[10] * vectorRight.v[2] + matrixLeft.m[14] * vectorRight.v[3], + matrixLeft.m[3] * vectorRight.v[0] + matrixLeft.m[7] * vectorRight.v[1] + matrixLeft.m[11] * vectorRight.v[2] + matrixLeft.m[15] * vectorRight.v[3] }; + return v; +#endif +} + +static __inline__ void GLKMatrix4MultiplyVector4Array(GLKMatrix4 matrix, GLKVector4 *vectors, size_t vectorCount) +{ + size_t i; + for (i=0; i < vectorCount; i++) + vectors[i] = GLKMatrix4MultiplyVector4(matrix, vectors[i]); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __GLK_MATRIX_4_H */ diff --git a/samples/C/NWMan.h b/samples/C/NWMan.h new file mode 100644 index 00000000..abcd2ddb --- /dev/null +++ b/samples/C/NWMan.h @@ -0,0 +1,99 @@ +#ifndef _NME_WMAN_H +#define _NME_WMAN_H + +// Internal window manager API + +#include "NCompat.h" + +START_HEAD + +#include "NPos.h" +#include "NUtil.h" +#include "NTypes.h" + +NTS(NWMan_event); + +NSTRUCT(NWMan, { + // Init stuff + bool (*init)(); + bool (*destroy)(); + + // Window stuff + bool (*create_window)(); + bool (*destroy_window)(); + + void (*swap_buffers)(); + + // Event stuff + bool (*next_event)(NWMan_event* event); + + // Time stuff + uint (*get_millis)(); + void (*sleep)(uint millis); + + // Info + int rshift_key; + int lshift_key; + int left_key; + int right_key; +}); + +NENUM(NWMan_event_type, { + N_WMAN_MOUSE_MOVE = 0, + N_WMAN_MOUSE_BUTTON = 1, + N_WMAN_MOUSE_WHEEL = 2, + + N_WMAN_KEYBOARD = 10, + + N_WMAN_QUIT = 20, + N_WMAN_RESIZE = 21, + N_WMAN_FOCUS = 22 +}); + +#define N_WMAN_MOUSE_LEFT 0 +#define N_WMAN_MOUSE_RIGHT 1 +#define N_WMAN_MOUSE_MIDDLE 2 + +NSTRUCT(NWMan_event, { + NWMan_event_type type; + + union { + // Mouse + + NPos2i mouse_pos; + + struct { + short id; + bool state; + } mouse_button; + + signed char mouse_wheel; // 1 if up, -1 if down + + // Keyboard + + struct { + int key; + bool state; + } keyboard; + + // Window + + bool window_quit; // Will always be true if WM_QUIT + + NPos2i window_size; + + bool window_focus; + }; +}); + +NWMan_event NWMan_event_new(NWMan_event_type type); + + +bool NWMan_init(); +bool NWMan_destroy(); + +extern NWMan N_WMan; + +END_HEAD + +#endif diff --git a/samples/C/Nightmare.h b/samples/C/Nightmare.h new file mode 100644 index 00000000..3b639c20 --- /dev/null +++ b/samples/C/Nightmare.h @@ -0,0 +1,27 @@ +#ifndef _NMEX_NIGHTMARE_H +#define _NMEX_NIGHTMARE_H + +//#define NMEX + +#include "../src/NCompat.h" + +START_HEAD + +#include "../src/NTypes.h" +#include "../src/NUtil.h" +#include "../src/NPorting.h" +#include "../src/NGlobals.h" +#include "../src/NLog.h" +#include "../src/NWMan.h" +#include "../src/NRsc.h" +#include "../src/NShader.h" +#include "../src/NSquare.h" +#include "../src/NImage.h" +#include "../src/NSprite.h" +#include "../src/NSpritesheet.h" +#include "../src/NEntity.h" +#include "../src/Game.h" + +END_HEAD + +#endif diff --git a/samples/C/ntru_encrypt.h b/samples/C/ntru_encrypt.h new file mode 100644 index 00000000..4893f6f9 --- /dev/null +++ b/samples/C/ntru_encrypt.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2014 FH Bielefeld + * + * This file is part of a FH Bielefeld project. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +/** + * @file ntru_encrypt.h + * Header for the internal API of ntru_encrypt.c. + * @brief header for encrypt.c + */ + +#ifndef PQC_ENCRYPT_H +#define PQC_ENCRYPT_H + + +#include "ntru_params.h" +#include "ntru_poly.h" +#include "ntru_string.h" + +#include +#include + + +/** + * encrypt the msg, using the math: + * e = (h ∗ r) + m (mod q) + * + * e = the encrypted poly + * + * h = the public key + * + * r = the random poly + * + * m = the message poly + * + * q = large mod + * + * @param msg_tern the message to encrypt, in ternary format + * @param pub_key the public key + * @param rnd the random poly (should have relatively small + * coefficients, but not restricted to {-1, 0, 1}) + * @param out the output poly which is in the range {0, q-1} + * (not ternary!) [out] + * @param params ntru_params the ntru context + */ +void +ntru_encrypt_poly( + const fmpz_poly_t msg_tern, + const fmpz_poly_t pub_key, + const fmpz_poly_t rnd, + fmpz_poly_t out, + const ntru_params *params); + +/** + * Encrypt a message in the form of a null-terminated char array and + * return a string. + * + * @param msg the message + * @param pub_key the public key + * @param rnd the random poly (should have relatively small + * coefficients, but not restricted to {-1, 0, 1}) + * @param params ntru_params the ntru context + * @return the newly allocated encrypted string + */ +string * +ntru_encrypt_string( + const string *msg, + const fmpz_poly_t pub_key, + const fmpz_poly_t rnd, + const ntru_params *params); + + +#endif /* PQC_ENCRYPT_H */ diff --git a/samples/Cool/list.cl b/samples/Cool/list.cl new file mode 100644 index 00000000..3d44813e --- /dev/null +++ b/samples/Cool/list.cl @@ -0,0 +1,26 @@ +(* This simple example of a list class is adapted from an example in the + Cool distribution. *) + +class List { + isNil() : Bool { true }; + head() : Int { { abort(); 0; } }; + tail() : List { { abort(); self; } }; + cons(i : Int) : List { + (new Cons).init(i, self) + }; +}; + +class Cons inherits List { + car : Int; -- The element in this list cell + cdr : List; -- The rest of the list + isNil() : Bool { false }; + head() : Int { car }; + tail() : List { cdr }; + init(i : Int, rest : List) : List { + { + car <- i; + cdr <- rest; + self; + } + }; +}; diff --git a/samples/Cool/sample.cl b/samples/Cool/sample.cl new file mode 100644 index 00000000..e8884990 --- /dev/null +++ b/samples/Cool/sample.cl @@ -0,0 +1,71 @@ +(* Refer to Alex Aiken, "The Cool Reference Manual": + http://theory.stanford.edu/~aiken/software/cool/cool-manual.pdf + for language specification. +*) + +-- Exhibit various language constructs +class Sample { + testCondition(x: Int): Bool { + if x = 0 + then false + else + if x < (1 + 2) * 3 + then true + else false + fi + fi + }; + + testLoop(y: Int): Bool { + while y > 0 loop + { + if not condition(y) + then y <- y / 2 + else y <- y - 1; + } + pool + }; + + testAssign(z: Int): Bool { + i : Int; + i <- ~z; + }; + + testCase(var: Sample): SELF_TYPE { + io : IO <- new IO; + case var of + a : A => io.out_string("Class type is A\n"); + b : B => io.out_string("Class type is B\n"); + s : Sample => io.out_string("Class type is Sample\n"); + o : Object => io.out_string("Class type is object\n"); + esac + }; + + testLet(i: Int): Int { + let (a: Int in + let(b: Int <- 3, c: Int <- 4 in + { + a <- 2; + a * b * 2 / c; + } + ) + ) + }; +}; + +-- Used to test subclasses +class A inherits Sample {}; +class B inherits A {}; + +class C { + main() : Int { + (new Sample).testLet(1) + }; +}; + +-- "Hello, world" example +class Main inherits IO { + main(): SELF_TYPE { + out_string("Hello, World.\n") + }; +}; diff --git a/samples/F#/Combinators.fs b/samples/F#/Combinators.fs new file mode 100644 index 00000000..409c524d --- /dev/null +++ b/samples/F#/Combinators.fs @@ -0,0 +1,49 @@ +namespace Nessos.FsPickler.Combinators + + open Nessos.FsPickler + open Nessos.FsPickler.Json + + /// Json pickling methods + [] + module Json = + + let private jsonSerializer = lazy(FsPickler.CreateJson(omitHeader = true)) + + /// + /// Pickles a value to Json. + /// + /// utilized pickler. + /// input value. + let pickle (pickler : Pickler<'T>) (value : 'T) : string = + jsonSerializer.Value.PickleToString (pickler, value) + + /// + /// Unpickles a value from Json. + /// + /// utilized pickler. + /// input pickle. + let unpickle (pickler : Pickler<'T>) (pickle : string) : 'T = + jsonSerializer.Value.UnPickleOfString (pickler, pickle) + + + /// Bson pickling methods + [] + module Bson = + + let private bsonPickler = lazy(FsPickler.CreateBson()) + + /// + /// Pickles a value to Bson. + /// + /// utilized pickler. + /// input value. + let pickle (pickler : Pickler<'T>) (value : 'T) : byte [] = + bsonPickler.Value.Pickle (pickler, value) + + /// + /// Unpickles a value from bson. + /// + /// utilized pickler. + /// input pickle. + let unpickle (pickler : Pickler<'T>) (pickle : byte []) : 'T = + bsonPickler.Value.UnPickle (pickler, pickle) \ No newline at end of file diff --git a/samples/F#/JsonFormat.fs b/samples/F#/JsonFormat.fs new file mode 100644 index 00000000..cf6aac61 --- /dev/null +++ b/samples/F#/JsonFormat.fs @@ -0,0 +1,65 @@ +namespace Nessos.FsPickler.Json + + open System + open System.IO + open System.Text + + open Newtonsoft.Json + + open Nessos.FsPickler + + /// + /// Factory methods for the Json serialization format. + /// + type JsonPickleFormatProvider internal (indent, omitHeader) as self = + + let isCustomSeq isTopLevelSequence = + isTopLevelSequence && self.OmitHeader && self.UseCustomTopLevelSequenceSeparator + + let mutable sequenceSeparator = " " + + member val Indent = indent with get,set + member val OmitHeader = omitHeader with get,set + member val UseCustomTopLevelSequenceSeparator = false with get,set + + member __.SequenceSeparator + with get () = sequenceSeparator + and set sep = + if sep <> null && String.IsNullOrWhiteSpace sep then + sequenceSeparator <- sep + else + invalidArg "SequenceSeparator" "should be non-null whitespace." + + interface ITextPickleFormatProvider with + member __.Name = "Json" + + // see discussion : https://github.com/nessos/FsPickler/issues/17 + member __.DefaultEncoding = new UTF8Encoding(false) :> Encoding + + member __.CreateWriter (stream, encoding, isTopLevelSequence, leaveOpen) = +#if NET40 + if leaveOpen then raise <| new NotSupportedException("'leaveOpen' not supported in .NET 40.") + let sw = new StreamWriter(stream, encoding) +#else + let sw = new StreamWriter(stream, encoding, 1024, leaveOpen) +#endif + let jw = new JsonTextWriter(sw) + new JsonPickleWriter(jw, __.OmitHeader, __.Indent, isCustomSeq isTopLevelSequence, sequenceSeparator, leaveOpen) :> _ + + member __.CreateReader (stream, encoding, isTopLevelSequence, leaveOpen) = +#if NET40 + if leaveOpen then raise <| new NotSupportedException("'leaveOpen' not supported in .NET 40.") + let sr = new StreamReader(stream, encoding) +#else + let sr = new StreamReader(stream, encoding, true, 1024, leaveOpen) +#endif + let jr = new JsonTextReader(sr) + new JsonPickleReader(jr, __.OmitHeader, isCustomSeq isTopLevelSequence, leaveOpen) :> _ + + member __.CreateWriter (textWriter, isTopLevelSequence, leaveOpen) = + let jw = new JsonTextWriter(textWriter) + new JsonPickleWriter(jw, __.OmitHeader, __.Indent, isCustomSeq isTopLevelSequence, sequenceSeparator, leaveOpen) :> _ + + member __.CreateReader (textReader, isTopLevelSequence, leaveOpen) = + let jr = new JsonTextReader(textReader) + new JsonPickleReader(jr, __.OmitHeader, isCustomSeq isTopLevelSequence, leaveOpen) :> _ \ No newline at end of file diff --git a/samples/F#/JsonReader.fs b/samples/F#/JsonReader.fs new file mode 100644 index 00000000..fdd90d3c --- /dev/null +++ b/samples/F#/JsonReader.fs @@ -0,0 +1,202 @@ +namespace Nessos.FsPickler.Json + + open System + open System.Collections.Generic + open System.Globalization + open System.IO + open System.Numerics + open System.Text + + open Newtonsoft.Json + + open Nessos.FsPickler + + /// + /// Json format deserializer + /// + type internal JsonPickleReader (jsonReader : JsonReader, omitHeader, isTopLevelSequence, leaveOpen) = + + do + jsonReader.CloseInput <- not leaveOpen + jsonReader.SupportMultipleContent <- isTopLevelSequence + + let isBsonReader = match jsonReader with :? Bson.BsonReader -> true | _ -> false + + let mutable depth = 0 + let arrayStack = new Stack () + do arrayStack.Push Int32.MinValue + + // do not write tag if omitting header or array element + let omitTag () = (omitHeader && depth = 0) || arrayStack.Peek() = depth - 1 + + interface IPickleFormatReader with + + member __.BeginReadRoot (tag : string) = + do jsonReader.Read() |> ignore + + if omitHeader then () else + + if jsonReader.TokenType <> JsonToken.StartObject then raise <| new FormatException("invalid json root object.") + else + do jsonReader.MoveNext() + let version = jsonReader.ReadPrimitiveAs false "FsPickler" + if version <> jsonFormatVersion then + let v = Version(version) + raise <| new FormatException(sprintf "Invalid FsPickler format version %O." version) + + let sTag = jsonReader.ReadPrimitiveAs false "type" + if tag <> sTag then + raise <| new InvalidPickleTypeException(tag, sTag) + + member __.EndReadRoot () = + if not omitHeader then jsonReader.Read() |> ignore + + member __.BeginReadObject (tag : string) = + + if not <| omitTag () then + jsonReader.ReadProperty tag + jsonReader.MoveNext () + + if isTopLevelSequence && depth = 0 then + arrayStack.Push depth + depth <- depth + 1 + ObjectFlags.IsSequenceHeader + + else + match jsonReader.TokenType with + | JsonToken.Null -> ObjectFlags.IsNull + | JsonToken.StartArray -> + jsonReader.MoveNext() + arrayStack.Push depth + depth <- depth + 1 + ObjectFlags.IsSequenceHeader + + | JsonToken.StartObject -> + do jsonReader.MoveNext() + depth <- depth + 1 + + if jsonReader.ValueAs () = "_flags" then + jsonReader.MoveNext() + let csvFlags = jsonReader.ValueAs() + jsonReader.MoveNext() + parseFlagCsv csvFlags + else + ObjectFlags.None + + | token -> raise <| new FormatException(sprintf "expected start of Json object but was '%O'." token) + + + member __.EndReadObject () = + if isTopLevelSequence && depth = 1 then + arrayStack.Pop () |> ignore + depth <- depth - 1 + jsonReader.Read() |> ignore + else + match jsonReader.TokenType with + | JsonToken.Null -> () + | JsonToken.EndObject -> depth <- depth - 1 + | JsonToken.EndArray -> + arrayStack.Pop() |> ignore + depth <- depth - 1 + + | token -> raise <| new FormatException(sprintf "expected end of Json object but was '%O'." token) + + if omitHeader && depth = 0 then () + else jsonReader.Read() |> ignore + + member __.SerializeUnionCaseNames = true + + member __.PreferLengthPrefixInSequences = false + member __.ReadNextSequenceElement () = + if isTopLevelSequence && depth = 1 then + jsonReader.TokenType <> JsonToken.None + else + jsonReader.TokenType <> JsonToken.EndArray + + member __.ReadCachedObjectId () = jsonReader.ReadPrimitiveAs false "id" + + member __.ReadBoolean tag = jsonReader.ReadPrimitiveAs (omitTag ()) tag + member __.ReadByte tag = jsonReader.ReadPrimitiveAs (omitTag ()) tag |> byte + member __.ReadSByte tag = jsonReader.ReadPrimitiveAs (omitTag ()) tag |> sbyte + + member __.ReadInt16 tag = jsonReader.ReadPrimitiveAs (omitTag ()) tag |> int16 + member __.ReadInt32 tag = jsonReader.ReadPrimitiveAs (omitTag ()) tag |> int + member __.ReadInt64 tag = jsonReader.ReadPrimitiveAs (omitTag ()) tag + + member __.ReadUInt16 tag = jsonReader.ReadPrimitiveAs (omitTag ()) tag |> uint16 + member __.ReadUInt32 tag = jsonReader.ReadPrimitiveAs (omitTag ()) tag |> uint32 + member __.ReadUInt64 tag = jsonReader.ReadPrimitiveAs (omitTag ()) tag |> uint64 + + member __.ReadSingle tag = + if not <| omitTag () then + jsonReader.ReadProperty tag + jsonReader.MoveNext() + + let value = + match jsonReader.TokenType with + | JsonToken.Float -> jsonReader.ValueAs () |> single + | JsonToken.String -> Single.Parse(jsonReader.ValueAs(), CultureInfo.InvariantCulture) + | _ -> raise <| new FormatException("not a float.") + + jsonReader.Read() |> ignore + value + + member __.ReadDouble tag = + if not <| omitTag () then + jsonReader.ReadProperty tag + jsonReader.MoveNext() + + let value = + match jsonReader.TokenType with + | JsonToken.Float -> jsonReader.ValueAs () + | JsonToken.String -> Double.Parse(jsonReader.ValueAs(), CultureInfo.InvariantCulture) + | _ -> raise <| new FormatException("not a float.") + + jsonReader.Read() |> ignore + value + + member __.ReadChar tag = let value = jsonReader.ReadPrimitiveAs (omitTag ()) tag in value.[0] + member __.ReadString tag = jsonReader.ReadPrimitiveAs (omitTag ()) tag + member __.ReadBigInteger tag = jsonReader.ReadPrimitiveAs (omitTag ()) tag |> BigInteger.Parse + + member __.ReadGuid tag = + if isBsonReader then + jsonReader.ReadPrimitiveAs (omitTag ()) tag + else + jsonReader.ReadPrimitiveAs (omitTag ()) tag |> Guid.Parse + + member __.ReadTimeSpan tag = jsonReader.ReadPrimitiveAs (omitTag ()) tag |> TimeSpan.Parse + member __.ReadDecimal tag = jsonReader.ReadPrimitiveAs (omitTag ()) tag |> decimal + + // BSON spec mandates the use of Unix time; + // this has millisecond precision which results in loss of accuracy w.r.t. ticks + // since the goal of FsPickler is to offer faithful representations of .NET objects + // we choose to override the spec and serialize ticks outright. + // see also https://json.codeplex.com/discussions/212067 + member __.ReadDate tag = + if isBsonReader then + let ticks = jsonReader.ReadPrimitiveAs (omitTag ()) tag + DateTime(ticks) + else + jsonReader.ReadPrimitiveAs (omitTag ()) tag + + member __.ReadBytes tag = + if not <| omitTag () then + jsonReader.ReadProperty tag + jsonReader.Read() |> ignore + + let bytes = + if jsonReader.TokenType = JsonToken.Null then null + elif isBsonReader then jsonReader.ValueAs () + else + let base64 = jsonReader.ValueAs () + Convert.FromBase64String base64 + + jsonReader.Read() |> ignore + + bytes + + member __.IsPrimitiveArraySerializationSupported = false + member __.ReadPrimitiveArray _ _ = raise <| new NotImplementedException() + + member __.Dispose () = (jsonReader :> IDisposable).Dispose() \ No newline at end of file diff --git a/samples/F#/JsonSerializer.fs b/samples/F#/JsonSerializer.fs new file mode 100644 index 00000000..15f4929a --- /dev/null +++ b/samples/F#/JsonSerializer.fs @@ -0,0 +1,85 @@ +namespace Nessos.FsPickler.Json + + open System + + open Nessos.FsPickler + + type internal OAttribute = System.Runtime.InteropServices.OptionalAttribute + type internal DAttribute = System.Runtime.InteropServices.DefaultParameterValueAttribute + + /// + /// Json pickler instance. + /// + type JsonSerializer = + inherit FsPicklerTextSerializer + + val private format : JsonPickleFormatProvider + + /// + /// Initializes a new Json pickler instance. + /// + /// indent out Json pickles. + /// omit FsPickler header in Json pickles. + /// specify a custom type name converter. + new ([] ?indent, [] ?omitHeader, [] ?typeConverter) = + let indent = defaultArg indent false + let omitHeader = defaultArg omitHeader false + let json = new JsonPickleFormatProvider(indent, omitHeader) + { + inherit FsPicklerTextSerializer(json, ?typeConverter = typeConverter) + format = json + } + + /// + /// Gets or sets whether Json output should be indented. + /// + member x.Indent + with get () = x.format.Indent + and set b = x.format.Indent <- b + + /// + /// Gets or sets whether FsPickler headers should be ignored in pickle format. + /// + member x.OmitHeader + with get () = x.format.OmitHeader + and set b = x.format.OmitHeader <- b + + /// + /// Gets or sets a non-null whitespace string that serves as a custom, top-level sequence separator. + /// + member x.SequenceSeparator + with get () = x.format.SequenceSeparator + and set sep = x.format.SequenceSeparator <- sep + + /// + /// Gets or sets whether top-level sequences should be serialized using the custom separator. + /// + member x.UseCustomTopLevelSequenceSeparator + with get () = x.format.UseCustomTopLevelSequenceSeparator + and set e = x.format.UseCustomTopLevelSequenceSeparator <- e + + /// + /// BSON pickler instance. + /// + type BsonSerializer([] ?typeConverter) = + inherit FsPicklerSerializer(new BsonPickleFormatProvider(), ?typeConverter = typeConverter) + + + /// FsPickler static methods. + type FsPickler = + + /// + /// Initializes a new Json pickler instance. + /// + /// indent out Json pickles. + /// omit FsPickler header in Json pickles. + /// specify a custom type name converter. + static member CreateJson([] ?indent, [] ?omitHeader, [] ?typeConverter) = + new JsonSerializer(?indent = indent, ?omitHeader = omitHeader, ?typeConverter = typeConverter) + + /// + /// Initializes a new Bson pickler instance. + /// + /// specify a custom type name converter. + static member CreateBson([] ?typeConverter) = + new BsonSerializer(?typeConverter = typeConverter) \ No newline at end of file diff --git a/samples/F#/JsonWriter.fs b/samples/F#/JsonWriter.fs new file mode 100644 index 00000000..bbb6ff24 --- /dev/null +++ b/samples/F#/JsonWriter.fs @@ -0,0 +1,142 @@ +namespace Nessos.FsPickler.Json + + open System + open System.IO + open System.Collections.Generic + + open Newtonsoft.Json + + open Nessos.FsPickler + + /// + /// Json format serializer. + /// + type internal JsonPickleWriter (jsonWriter : JsonWriter, omitHeader, indented, isTopLevelSequence, separator, leaveOpen) = + + do + jsonWriter.Formatting <- if indented then Formatting.Indented else Formatting.None + jsonWriter.CloseOutput <- not leaveOpen + + let isBsonWriter = match jsonWriter with :? Bson.BsonWriter -> true | _ -> false + + let mutable depth = 0 + let mutable isTopLevelSequenceHead = false + let mutable currentValueIsNull = false + + let arrayStack = new Stack () + do arrayStack.Push Int32.MinValue + + // do not write tag if omitting header or array element + let omitTag () = (omitHeader && depth = 0) || arrayStack.Peek() = depth - 1 + + interface IPickleFormatWriter with + + member __.BeginWriteRoot (tag : string) = + if omitHeader then () else + + jsonWriter.WriteStartObject() + writePrimitive jsonWriter false "FsPickler" jsonFormatVersion + writePrimitive jsonWriter false "type" tag + + member __.EndWriteRoot () = + if not omitHeader then jsonWriter.WriteEnd() + + member __.BeginWriteObject (tag : string) (flags : ObjectFlags) = + + if not <| omitTag () then + jsonWriter.WritePropertyName tag + + if flags.HasFlag ObjectFlags.IsNull then + currentValueIsNull <- true + jsonWriter.WriteNull() + + elif flags.HasFlag ObjectFlags.IsSequenceHeader then + if isTopLevelSequence && depth = 0 then + isTopLevelSequenceHead <- true + else + jsonWriter.WriteStartArray() + + arrayStack.Push depth + depth <- depth + 1 + else + jsonWriter.WriteStartObject() + depth <- depth + 1 + + if flags = ObjectFlags.None then () + else + let flagCsv = mkFlagCsv flags + writePrimitive jsonWriter false "_flags" flagCsv + + member __.EndWriteObject () = + if currentValueIsNull then + currentValueIsNull <- false + else + depth <- depth - 1 + if arrayStack.Peek () = depth then + if isTopLevelSequence && depth = 0 then () + else + jsonWriter.WriteEndArray() + + arrayStack.Pop () |> ignore + else + jsonWriter.WriteEndObject() + + member __.SerializeUnionCaseNames = true + + member __.PreferLengthPrefixInSequences = false + member __.WriteNextSequenceElement hasNext = + if isTopLevelSequence && depth = 1 then + if isTopLevelSequenceHead then + isTopLevelSequenceHead <- false + else + jsonWriter.WriteWhitespace separator + + member __.WriteCachedObjectId id = writePrimitive jsonWriter false "id" id + + member __.WriteBoolean (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + member __.WriteByte (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + member __.WriteSByte (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + + member __.WriteInt16 (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + member __.WriteInt32 (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + member __.WriteInt64 (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + + member __.WriteUInt16 (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + member __.WriteUInt32 (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + member __.WriteUInt64 (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + + member __.WriteSingle (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + member __.WriteDouble (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + member __.WriteDecimal (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag (string value) + + member __.WriteChar (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + member __.WriteString (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + member __.WriteBigInteger (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag (string value) + + member __.WriteGuid (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag value + member __.WriteTimeSpan (tag : string) value = writePrimitive jsonWriter (omitTag ()) tag (string value) + + // BSON spec mandates the use of Unix time; + // this has millisecond precision which results in loss of accuracy w.r.t. ticks + // since the goal of FsPickler is to offer faithful representations of .NET objects + // we choose to override the spec and serialize ticks outright. + // see also https://json.codeplex.com/discussions/212067 + member __.WriteDate (tag : string) value = + if isBsonWriter then + writePrimitive jsonWriter (omitTag ()) tag value.Ticks + else + writePrimitive jsonWriter (omitTag ()) tag value + + member __.WriteBytes (tag : string) (value : byte []) = + if not <| omitTag () then + jsonWriter.WritePropertyName tag + + if obj.ReferenceEquals(value, null) then + jsonWriter.WriteNull() + else + jsonWriter.WriteValue value + + member __.IsPrimitiveArraySerializationSupported = false + member __.WritePrimitiveArray _ _ = raise <| NotSupportedException() + + member __.Dispose () = jsonWriter.Flush() \ No newline at end of file diff --git a/samples/F#/PerformanceTesters.fs b/samples/F#/PerformanceTesters.fs new file mode 100644 index 00000000..c5eb20d2 --- /dev/null +++ b/samples/F#/PerformanceTesters.fs @@ -0,0 +1,68 @@ +namespace Nessos.FsPickler.Tests + + open PerfUtil + open PerfUtil.NUnit + + open NUnit.Framework + + open Nessos.FsPickler + open Nessos.FsPickler.Json + + [] + type PerfTester () = + inherit NUnitPerf () + + let tests = PerfTest.OfModuleMarker () + + override __.PerfTests = tests + + + type ``Serializer Comparison`` () = + inherit PerfTester() + + let fsp = FsPickler.initBinary() + let bfs = new BinaryFormatterSerializer() :> Serializer + let ndc = new NetDataContractSerializer() :> Serializer + let jdn = new JsonDotNetSerializer() :> Serializer + let bdn = new JsonDotNetBsonSerializer () :> Serializer + let pbn = new ProtoBufSerializer() :> Serializer + let ssj = new ServiceStackJsonSerializer() :> Serializer + let sst = new ServiceStackTypeSerializer() :> Serializer + + let comparer = new WeightedComparer(spaceFactor = 0.2, leastAcceptableImprovementFactor = 1.) + let tester = new ImplementationComparer<_>(fsp, [bfs;ndc;jdn;bdn;pbn;ssj;sst], throwOnError = true, warmup = true, comparer = comparer) + + override __.PerfTester = tester :> _ + + + type ``FsPickler Formats Comparison`` () = + inherit PerfTester () + + let binary = FsPickler.initBinary() + let json = FsPickler.initJson() + let bson = FsPickler.initBson() + let xml = FsPickler.initXml() + + let tester = new ImplementationComparer<_>(binary, [json ; bson; xml], warmup = true, throwOnError = false) + + override __.PerfTester = tester :> _ + + + type ``Past FsPickler Versions Comparison`` () = + inherit PerfTester () + + let persistResults = true + let persistenceFile = "fspPerf.xml" + + let fsp = FsPickler.initBinary() + let version = typeof.Assembly.GetName().Version + let comparer = new WeightedComparer(spaceFactor = 0.2, leastAcceptableImprovementFactor = 0.8) + let tester = + new PastImplementationComparer( + fsp, version, historyFile = persistenceFile, throwOnError = true, warmup = true, comparer = comparer) + + override __.PerfTester = tester :> _ + + [] + member __.Persist() = + if persistResults then tester.PersistCurrentResults () \ No newline at end of file diff --git a/samples/F#/PerformanceTests.fs b/samples/F#/PerformanceTests.fs new file mode 100644 index 00000000..c3d01356 --- /dev/null +++ b/samples/F#/PerformanceTests.fs @@ -0,0 +1,207 @@ +namespace Nessos.FsPickler.Tests + + open System + open System.Collections.Generic + + open PerfUtil + + open Nessos.FsPickler + open Nessos.FsPickler.Tests.Serializer + open Nessos.FsPickler.Tests.TestTypes + + module PerformanceTests = + + type Marker = class end + + let guid = Guid.NewGuid() + + [] + let ``Value: Guid`` s = roundtrip guid s + + let date = DateTime.Now + + [] + let ``Value: DateTime`` s = roundtrip date s + + [] + let ``Value: String`` s = roundtrip stringValue s + + + let boxed = box ([| 1 .. 1000 |], "lorem ipsum") + + [] + let ``Boxed Object`` s = roundtrip boxed s + + let fsClass = new Class(42, stringValue) + + [] + let ``Class: Simple F# Class`` s = roundtrip fsClass s + + let serializableClass = new SerializableClass<_>(42, stringValue, [|1..1000|]) + + [] + let ``Class: ISerializable`` s = roundtrip serializableClass s + + let boxedClass = box(Some 42) + + [] + let ``Subtype Resolution`` s = roundtrip boxedClass s + + let floatArray = Array.init 100000 (fun i -> float i) + + [] + let ``Array: Float`` s = roundtrip floatArray s + + let intArray = Array.init 100000 id + + [] + let ``Array: Int`` s = roundtrip intArray s + + let stringArray = Array.init 10000 (fun i -> stringValue + string i) + + [] + let ``Array: String`` s = roundtrip stringArray s + + let kvarr = [|1..10000|] |> Array.map (fun i -> i, string i) + + [] + let ``Array: Key-Value Pairs`` s = roundtrip kvarr s + + let duArray = [| for i in 1 .. 10000 -> (Something ("asdasdasdas", i)) |] + + [] + let ``Array: Discriminated Unions`` s = roundtrip duArray s + + let objArray = + [| + box 2; box 3; box "hello" ; box <| Some 3; box(2,3) ; + box <| new Class(2, stringValue) ; box <| new SerializableClass(2, stringValue, Some 12); + box stringValue + |] + + [] + let ``Array: Objects`` s = roundtrip objArray s + + + let array3D = Array3D.init 100 100 100 (fun i j k -> float (i * j + k)) + + [] + let ``Array: Rank-3 Float`` s = roundtrip array3D s + + let bclDict = dict [ for i in 1 .. 1000 -> (string i, i)] + + [] + let ``.NET Dictionary`` s = roundtrip bclDict s + + let bclStack = new Stack([for i in 1 .. 1000 -> string i]) + + [] + let ``.NET Stack`` s = roundtrip bclStack s + + let bclList = new List([for i in 1 .. 1000 -> string i, i]) + + [] + let ``.NET List`` s = roundtrip bclList s + + let bclSet = new SortedSet<_>([for i in 1 .. 1000 -> string i]) + + [] + let ``.NET Set`` s = roundtrip bclSet s + + let smallTuple = (1, DateTime.Now,"hello") + + [] + let ``FSharp: Tuple Small`` s = roundtrip smallTuple s + + let largeTuple = (stringValue, 1, 2, 3, true, "", Some(3.14, [2]), 3, 2, 1, stringValue) + + [] + let ``FSharp: Tuple Large`` s = + roundtrip largeTuple s + + let intList = [1..1000] + + [] + let ``FSharp: List Int`` s = roundtrip intList s + + let stringList = [ for i in 1 .. 1000 -> stringValue + string i ] + + [] + let ``FSharp: List String`` s = roundtrip stringList s + + let pairList = [ for i in 1 .. 1000 -> (string i, i) ] + + [] + let ``FSharp: List Key-Value`` s = roundtrip pairList s + + let nestedLst = let n = [1..1000] in [for _ in 1 .. 100 -> n] + + [] + let ``FSharp: List Nested`` s = roundtrip nestedLst s + + let union = SomethingElse(stringValue, 42, box (Some 42)) + + [] + let ``FSharp: Union`` s = roundtrip union s + + let record = { Int = 42 ; String = stringValue ; Tuple = (13, "") } + + [] + let ``FSharp: Record`` s = roundtrip record s + + let peano = int2Peano 100 + + [] + let ``FSharp: Peano Rectype`` s = roundtrip peano s + + let closure = (@) [ Some([1..100], Set.ofList [1..100]) ] + + [] + let ``FSharp: Curried Function`` s = roundtrip closure s + + let binTree = mkTree 10 + + [] + let ``FSharp: Binary Tree`` s = roundtrip binTree s + + let intSet = [1..1000] |> List.map string |> set + + [] + let ``FSharp: Set`` s = roundtrip intSet s + + let fsMap = [1..1000] |> Seq.map (fun i -> (string i,i)) |> Map.ofSeq + + [] + let ``FSharp: Map`` s = roundtrip fsMap s + + let testType = typeof> + + [] + let ``Reflection: Type`` s = roundtrip testType s + + let quotationSmall = <@ fun x -> pown 2 x @> + + let quotationLarge = + <@ + async { + let rec fibAsync n = + async { + match n with + | _ when n < 0 -> return invalidArg "negative" "n" + | _ when n < 2 -> return n + | n -> + let! fn = fibAsync (n-1) + let! fnn = fibAsync (n-2) + return fn + fnn + } + + let! values = [1..100] |> Seq.map fibAsync |> Async.Parallel + return Seq.sum values + } + @> + + [] + let ``FSharp: Quotation Small`` s = roundtrip quotationSmall s + + [] + let ``FSharp: Quotation Large`` s = roundtrip quotationLarge s \ No newline at end of file diff --git a/samples/F#/sample.fs b/samples/F#/sample.fs new file mode 100644 index 00000000..2b690f10 --- /dev/null +++ b/samples/F#/sample.fs @@ -0,0 +1,15 @@ +module Sample + +open System + +type Foo = + { + Bar : string + } + +type Baz = interface end + +let Sample1(xs : int list) : string = + xs + |> List.map (fun x -> string x) + |> String.concat "," diff --git a/samples/Forth/core.fs b/samples/Forth/core.fs new file mode 100644 index 00000000..4a13e217 --- /dev/null +++ b/samples/Forth/core.fs @@ -0,0 +1,252 @@ +: immediate lastxt @ dup c@ negate swap c! ; + +: \ source nip >in ! ; immediate \ Copyright 2004, 2012 Lars Brinkhoff + +: char \ ( "word" -- char ) + bl-word here 1+ c@ ; + +: ahead here 0 , ; + +: resolve here swap ! ; + +: ' bl-word here find 0branch [ ahead ] exit [ resolve ] 0 ; + +: postpone-nonimmediate [ ' literal , ' compile, ] literal , ; + +: create dovariable_code header, reveal ; + +create postponers + ' postpone-nonimmediate , + ' abort , + ' , , + +: word \ ( char "string" -- caddr ) + drop bl-word here ; + +: postpone \ ( C: "word" -- ) + bl word find 1+ cells postponers + @ execute ; immediate + +: unresolved \ ( C: "word" -- orig ) + postpone postpone postpone ahead ; immediate + +: chars \ ( n1 -- n2 ) + ; + +: else \ ( -- ) ( C: orig1 -- orig2 ) + unresolved branch swap resolve ; immediate + +: if \ ( flag -- ) ( C: -- orig ) + unresolved 0branch ; immediate + +: then \ ( -- ) ( C: orig -- ) + resolve ; immediate + +: [char] \ ( "word" -- ) + char postpone literal ; immediate + +: (does>) lastxt @ dodoes_code over >code ! r> swap >does ! ; + +: does> postpone (does>) ; immediate + +: begin \ ( -- ) ( C: -- dest ) + here ; immediate + +: while \ ( x -- ) ( C: dest -- orig dest ) + unresolved 0branch swap ; immediate + +: repeat \ ( -- ) ( C: orig dest -- ) + postpone branch , resolve ; immediate + +: until \ ( x -- ) ( C: dest -- ) + postpone 0branch , ; immediate + +: recurse lastxt @ compile, ; immediate + +: pad \ ( -- addr ) + here 1024 + ; + +: parse \ ( char "string" -- addr n ) + pad >r begin + source? if else 0 0 then + while + r@ c! r> 1+ >r + repeat 2drop pad r> over - ; + +: ( \ ( "string" -- ) + [ char ) ] literal parse 2drop ; immediate + \ TODO: If necessary, refill and keep parsing. + +: string, ( addr n -- ) + here over allot align swap cmove ; + +: (s") ( -- addr n ) ( R: ret1 -- ret2 ) + r> dup @ swap cell+ 2dup + aligned >r swap ; + +create squote 128 allot + +: s" ( "string" -- addr n ) + state @ if + postpone (s") [char] " parse dup , string, + else + [char] " parse >r squote r@ cmove squote r> + then ; immediate + +: (abort") ( ... addr n -- ) ( R: ... -- ) + cr type cr abort ; + +: abort" ( ... x "string" -- ) ( R: ... -- ) + postpone if postpone s" postpone (abort") postpone then ; immediate + +\ ---------------------------------------------------------------------- + +( Core words. ) + +\ TODO: # +\ TODO: #> +\ TODO: #s + +: and ( x y -- x&y ) nand invert ; + +: * 1 2>r 0 swap begin r@ while + r> r> swap 2dup dup + 2>r and if swap over + swap then dup + + repeat r> r> 2drop drop ; + +\ TODO: */mod + +: +loop ( -- ) ( C: nest-sys -- ) + postpone (+loop) postpone 0branch , postpone unloop ; immediate + +: space bl emit ; + +: ?.- dup 0 < if [char] - emit negate then ; + +: digit [char] 0 + emit ; + +: (.) base @ /mod ?dup if recurse then digit ; + +: ." ( "string" -- ) postpone s" postpone type ; immediate + +: . ( x -- ) ?.- (.) space ; + +: postpone-number ( caddr -- ) + 0 0 rot count >number dup 0= if + 2drop nip + postpone (literal) postpone (literal) postpone , + postpone literal postpone , + else + ." Undefined: " type cr abort + then ; + +' postpone-number postponers cell+ ! + +: / ( x y -- x/y ) /mod nip ; + +: 0< ( n -- flag ) 0 < ; + +: 1- ( n -- n-1 ) -1 + ; + +: 2! ( x1 x2 addr -- ) swap over ! cell+ ! ; + +: 2* ( n -- 2n ) dup + ; + +\ Kernel: 2/ + +: 2@ ( addr -- x1 x2 ) dup cell+ @ swap @ ; + +\ Kernel: 2drop +\ Kernel: 2dup + +\ TODO: 2over ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 ) +\ 3 pick 3 pick ; + +\ TODO: 2swap + +\ TODO: <# + +: abs ( n -- |n| ) + dup 0< if negate then ; + +\ TODO: accept + +: c, ( n -- ) + here c! 1 chars allot ; + +: char+ ( n1 -- n2 ) + 1+ ; + +: constant create , does> @ ; + +: decimal ( -- ) + 10 base ! ; + +: depth ( -- n ) + data_stack 100 cells + 'SP @ - /cell / 2 - ; + +: do ( n1 n2 -- ) ( R: -- loop-sys ) ( C: -- do-sys ) + postpone 2>r here ; immediate + +\ TODO: environment? +\ TODO: evaluate +\ TODO: fill +\ TODO: fm/mod ) +\ TODO: hold + +: j ( -- x1 ) ( R: x1 x2 x3 -- x1 x2 x3 ) + 'RP @ 3 cells + @ ; + +\ TODO: leave + +: loop ( -- ) ( C: nest-sys -- ) + postpone 1 postpone (+loop) + postpone 0branch , + postpone unloop ; immediate + +: lshift begin ?dup while 1- swap dup + swap repeat ; + +: rshift 1 begin over while dup + swap 1- swap repeat nip + 2>r 0 1 begin r@ while + r> r> 2dup swap dup + 2>r and if swap over + swap then dup + + repeat r> r> 2drop drop ; + +: max ( x y -- max[x,y] ) + 2dup > if drop else nip then ; + +\ Kernel: min +\ TODO: mod +\ TODO: move + +: (quit) ( R: ... -- ) + return_stack 100 cells + 'RP ! + 0 'source-id ! tib ''source ! #tib ''#source ! + postpone [ + begin + refill + while + interpret state @ 0= if ." ok" cr then + repeat + bye ; + +' (quit) ' quit >body cell+ ! + +\ TODO: s>d +\ TODO: sign +\ TODO: sm/rem + +: spaces ( n -- ) + 0 do space loop ; + +\ TODO: u. + +: signbit ( -- n ) -1 1 rshift invert ; + +: xor ( x y -- x^y ) 2dup nand >r r@ nand swap r> nand nand ; + +: u< ( x y -- flag ) signbit xor swap signbit xor > ; + +\ TODO: um/mod + +: variable ( "word" -- ) + create /cell allot ; + +: ['] \ ( C: "word" -- ) + ' postpone literal ; immediate diff --git a/samples/GLSL/recurse1.fs b/samples/GLSL/recurse1.fs new file mode 100644 index 00000000..66b4c3fe --- /dev/null +++ b/samples/GLSL/recurse1.fs @@ -0,0 +1,48 @@ +#version 330 core + +// cross-unit recursion + +void main() {} + +// two-level recursion + +float cbar(int); + +void cfoo(float) +{ + cbar(2); +} + +// four-level, out of order + +void CB(); +void CD(); +void CA() { CB(); } +void CC() { CD(); } + +// high degree + +void CBT(); +void CDT(); +void CAT() { CBT(); CBT(); CBT(); } +void CCT() { CDT(); CDT(); CBT(); } + +// not recursive + +void norA() {} +void norB() { norA(); } +void norC() { norA(); } +void norD() { norA(); } +void norE() { norB(); } +void norF() { norB(); } +void norG() { norE(); } +void norH() { norE(); } +void norI() { norE(); } + +// not recursive, but with a call leading into a cycle if ignoring direction + +void norcA() { } +void norcB() { norcA(); } +void norcC() { norcB(); } +void norcD() { norcC(); norcB(); } // head of cycle +void norcE() { norcD(); } // lead into cycle diff --git a/samples/Gosu/Ronin.gs b/samples/Gosu/Ronin.gs new file mode 100644 index 00000000..dfbdee7b --- /dev/null +++ b/samples/Gosu/Ronin.gs @@ -0,0 +1,238 @@ +/** + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ + +package ronin + +uses gw.util.concurrent.LockingLazyVar +uses gw.lang.reflect.* +uses java.lang.* +uses java.io.* +uses ronin.config.* +uses org.slf4j.* + +/** + * The central location for Ronin utility methods. Controllers and templates should generally access the + * methods and properties they inherit from {@link ronin.IRoninUtils} instead of using the methods and + * properties here. + */ +class Ronin { + + // One static field to rule the all... + static var _CONFIG : IRoninConfig as Config + + // And one thread local to bind them + static var _CURRENT_REQUEST = new ThreadLocal(); + + // That's inconstructable + private construct() {} + + internal static function init(servlet : RoninServlet, m : ApplicationMode, src : File) { + if(_CONFIG != null) { + throw "Cannot initialize a Ronin application multiple times!" + } + var cfg = TypeSystem.getByFullNameIfValid("config.RoninConfig") + var defaultWarning = false + if(cfg != null) { + var ctor = cfg.TypeInfo.getConstructor({ronin.config.ApplicationMode, ronin.RoninServlet}) + if(ctor == null) { + throw "config.RoninConfig must have a constructor with the same signature as ronin.config.RoninConfig" + } + _CONFIG = ctor.Constructor.newInstance({m, servlet}) as IRoninConfig + } else { + _CONFIG = new DefaultRoninConfig(m, servlet) + defaultWarning = true + } + var roninLogger = TypeSystem.getByFullNameIfValid("ronin.RoninLoggerFactory") + if(roninLogger != null) { + roninLogger.TypeInfo.getMethod("init", {ronin.config.LogLevel}).CallHandler.handleCall(null, {LogLevel}) + } + if(defaultWarning) { + log("No configuration was found at config.RoninConfig, using the default configuration...", :level=WARN) + } + Quartz.maybeStart() + ReloadManager.setSourceRoot(src) + } + + internal static property set CurrentRequest(req : RoninRequest) { + _CURRENT_REQUEST.set(req) + } + + //============================================ + // Public API + //============================================ + + /** + * The trace handler for the current request. + */ + static property get CurrentTrace() : Trace { + return CurrentRequest?.Trace + } + + /** + * Ronin's representation of the current request. + */ + static property get CurrentRequest() : RoninRequest { + return _CURRENT_REQUEST.get() + } + + /** + * The mode in which this application is running. + */ + static property get Mode() : ApplicationMode { + return _CONFIG?.Mode ?: TESTING + } + + /** + * The log level at and above which log messages should be displayed. + */ + static property get LogLevel() : LogLevel { + return _CONFIG?.LogLevel ?: DEBUG + } + + /** + * Whether or not to display detailed trace information on each request. + */ + static property get TraceEnabled() : boolean { + return _CONFIG != null ? _CONFIG.TraceEnabled : true + } + + /** + * The default controller method to call when no method name is present in the request URL. + */ + static property get DefaultAction() : String { + return _CONFIG?.DefaultAction + } + + /** + * The default controller to call when no controller name is present in the request URL. + */ + static property get DefaultController() : Type { + return _CONFIG?.DefaultController + } + + /** + * The servlet responsible for handling Ronin requests. + */ + static property get RoninServlet() : RoninServlet { + return _CONFIG?.RoninServlet + } + + /** + * The handler for request processing errors. + */ + static property get ErrorHandler() : IErrorHandler { + return _CONFIG?.ErrorHandler + } + + /** + * The custom handler for logging messages. + */ + static property get LogHandler() : ILogHandler { + return _CONFIG?.LogHandler + } + + /** + * Logs a message using the configured log handler. + * @param msg The text of the message to log, or a block which returns said text. + * @param level (Optional) The level at which to log the message. + * @param component (Optional) The logical component from whence the message originated. + * @param exception (Optional) An exception to associate with the message. + */ + static function log(msg : Object, level : LogLevel = null, component : String = null, exception : java.lang.Throwable = null) { + if(level == null) { + level = INFO + } + if(LogLevel <= level) { + var msgStr : String + if(msg typeis block():String) { + msgStr = (msg as block():String)() + } else { + msgStr = msg as String + } + if(_CONFIG?.LogHandler != null) { + _CONFIG.LogHandler.log(msgStr, level, component, exception) + } else { + switch(level) { + case TRACE: + LoggerFactory.getLogger(component?:Logger.ROOT_LOGGER_NAME).trace(msgStr, exception) + break + case DEBUG: + LoggerFactory.getLogger(component?:Logger.ROOT_LOGGER_NAME).debug(msgStr, exception) + break + case INFO: + LoggerFactory.getLogger(component?:Logger.ROOT_LOGGER_NAME).info(msgStr, exception) + break + case WARN: + LoggerFactory.getLogger(component?:Logger.ROOT_LOGGER_NAME).warn(msgStr, exception) + break + case ERROR: + case FATAL: + LoggerFactory.getLogger(component?:Logger.ROOT_LOGGER_NAME).error(msgStr, exception) + break + } + } + } + } + + /** + * The caches known to Ronin. + */ + static enum CacheStore { + REQUEST, + SESSION, + APPLICATION + } + + /** + * Retrieves a value from a cache, or computes and stores it if it is not in the cache. + * @param value A block which will compute the desired value. + * @param name (Optional) A unique identifier for the value. Default is null, which means one will be + * generated from the type of the value. + * @param store (Optional) The cache store used to retrieve or store the value. Default is the request cache. + * @return The retrieved or computed value. + */ + static function cache(value : block():T, name : String = null, store : CacheStore = null) : T { + if(store == null or store == REQUEST) { + return _CONFIG.RequestCache.getValue(value, name) + } else if (store == SESSION) { + return _CONFIG.SessionCache.getValue(value, name) + } else if (store == APPLICATION) { + return _CONFIG.ApplicationCache.getValue(value, name) + } else { + throw "Don't know about CacheStore ${store}" + } + } + + /** + * Invalidates a cached value in a cache. + * @param name The unique identifier for the value. + * @param store The cache store in which to invalidate the value. + */ + static function invalidate(name : String, store : CacheStore) { + if(store == null or store == REQUEST) { + _CONFIG.RequestCache.invalidate(name) + } else if (store == SESSION) { + _CONFIG.SessionCache.invalidate(name) + } else if (store == APPLICATION) { + _CONFIG.ApplicationCache.invalidate(name) + } else { + throw "Don't know about CacheStore ${store}" + } + } + + + /** + * Detects changes made to resources in the Ronin application and + * reloads them. This function should only be called when Ronin is + * in development mode. + */ + static function loadChanges() { + ReloadManager.detectAndReloadChangedResources() + } + +} diff --git a/samples/Gradle/build.gradle b/samples/Gradle/build.gradle new file mode 100644 index 00000000..190eb3f6 --- /dev/null +++ b/samples/Gradle/build.gradle @@ -0,0 +1,18 @@ +apply plugin: GreetingPlugin + +greeting.message = 'Hi from Gradle' + +class GreetingPlugin implements Plugin { + void apply(Project project) { + // Add the 'greeting' extension object + project.extensions.create("greeting", GreetingPluginExtension) + // Add a task that uses the configuration + project.task('hello') << { + println project.greeting.message + } + } +} + +class GreetingPluginExtension { + def String message = 'Hello from GreetingPlugin' +} diff --git a/samples/Gradle/builder.gradle b/samples/Gradle/builder.gradle new file mode 100644 index 00000000..342be2fd --- /dev/null +++ b/samples/Gradle/builder.gradle @@ -0,0 +1,20 @@ +apply plugin: GreetingPlugin + +greeting { + message = 'Hi' + greeter = 'Gradle' +} + +class GreetingPlugin implements Plugin { + void apply(Project project) { + project.extensions.create("greeting", GreetingPluginExtension) + project.task('hello') << { + println "${project.greeting.message} from ${project.greeting.greeter}" + } + } +} + +class GreetingPluginExtension { + String message + String greeter +} diff --git a/samples/JavaScript/chart_composers.gs b/samples/JavaScript/chart_composers.gs new file mode 100644 index 00000000..3b6f4400 --- /dev/null +++ b/samples/JavaScript/chart_composers.gs @@ -0,0 +1,78 @@ +/* +License +Copyright [2013] [Farruco Sanjurjo Arcay] + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +*/ + +var TagsTotalPerMonth; + +TagsTotalPerMonth = (function(){ + function TagsTotalPerMonth(){}; + + TagsTotalPerMonth.getDatasource = function (category, months, values){ + return new CategoryMonthlyExpenseBarChartDataSource(category, months, values); + }; + + TagsTotalPerMonth.getType = function (){ return Charts.ChartType.COLUMN}; + + return TagsTotalPerMonth; +})(); + + +var TagsTotalPerMonthWithMean; + +TagsTotalPerMonthWithMean = (function(){ + function TagsTotalPerMonthWithMean(){}; + + TagsTotalPerMonthWithMean.getDatasource = function (category, months, values){ + return new CategoryMonthlyWithMeanExpenseDataSource(category, months, values); + }; + + TagsTotalPerMonthWithMean.getType = function (){ return Charts.ChartType.LINE}; + + return TagsTotalPerMonthWithMean; +})(); + + +var TagsAccumulatedPerMonth; + +TagsAccumulatedPerMonth = (function(){ + function TagsAccumulatedPerMonth(){}; + + TagsAccumulatedPerMonth.getDatasource = function (category, months, values){ + return new CategoryMonthlyAccumulated(category, months, values); + }; + + TagsAccumulatedPerMonth.getType = function (){ return Charts.ChartType.AREA}; + + return TagsAccumulatedPerMonth; +})(); + +var MonthTotalsPerTags; + +MonthTotalsPerTags = (function(){ + function MonthTotalsPerTags(){}; + + MonthTotalsPerTags.getDatasource = function (month, tags, values){ + return new CategoryExpenseDataSource(tags, month, values); + }; + + MonthTotalsPerTags.getType = function (){ return Charts.ChartType.PIE; }; + + return MonthTotalsPerTags; +})(); + +var SavingsFlowChartComposer = (function(){ + function SavingsFlowChartComposer(){}; + + SavingsFlowChartComposer.getDatasource = function(months, values){ + return new SavingsFlowDataSource(months, values); + }; + + SavingsFlowChartComposer.getType = function(){ return Charts.ChartType.COLUMN; }; + + return SavingsFlowChartComposer; +})(); diff --git a/samples/JavaScript/itau.gs b/samples/JavaScript/itau.gs new file mode 100644 index 00000000..d745a3fb --- /dev/null +++ b/samples/JavaScript/itau.gs @@ -0,0 +1,150 @@ +/* +The MIT License (MIT) + +Copyright (c) 2014 Thiago Brandão Damasceno + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +// based on http://ctrlq.org/code/19053-send-to-google-drive +function sendToGoogleDrive() { + + var gmailLabels = 'inbox'; + var driveFolder = 'Itaú Notifications'; + var spreadsheetName = 'itau'; + var archiveLabel = 'itau.processed'; + var itauNotificationEmail = 'comunicacaodigital@itau-unibanco.com.br'; + var filter = "from: " + + itauNotificationEmail + + " -label:" + + archiveLabel + + " label:" + + gmailLabels; + + // Create label for 'itau.processed' if it doesn't exist + var moveToLabel = GmailApp.getUserLabelByName(archiveLabel); + + if (!moveToLabel) { + moveToLabel = GmailApp.createLabel(archiveLabel); + } + + // Create folder 'Itaú Notifications' if it doesn't exist + var folders = DriveApp.getFoldersByName(driveFolder); + var folder; + + if (folders.hasNext()) { + folder = folders.next(); + } else { + folder = DriveApp.createFolder(driveFolder); + } + + // Create spreadsheet file 'itau' if it doesn't exist + var files = folder.getFilesByName(spreadsheetName); + + // File is in DriveApp + // Doc is in SpreadsheetApp + // They are not interchangeable + var file, doc; + + // Confusing :\ + // As per: https://code.google.com/p/google-apps-script-issues/issues/detail?id=3578 + if (files.hasNext()){ + file = files.next(); + doc = SpreadsheetApp.openById(file.getId()); + } else { + doc = SpreadsheetApp.create(spreadsheetName); + file = DriveApp.getFileById(doc.getId()); + folder.addFile(file); + DriveApp.removeFile(file); + } + + var sheet = doc.getSheets()[0]; + + // Append header if first line + if(sheet.getLastRow() == 0){ + sheet.appendRow(['Conta', 'Operação', 'Valor', 'Data', 'Hora', 'Email ID']); + } + + var message, messages, account, operation, value, date, hour, emailID, plainBody; + var accountRegex = /Conta: (XXX[0-9\-]+)/; + var operationRegex = /Tipo de operação: ([A-Z]+)/; + var paymentRegex = /Pagamento de ([0-9A-Za-z\-]+)\ ?([0-9]+)?/; + var valueRegex = /Valor: R\$ ([0-9\,\.]+)/; + var dateRegex = /Data: ([0-9\/]+)/; + var hourRegex = /Hora: ([0-9\:]+)/; + var emailIDRegex = /E-mail nº ([0-9]+)/; + + var threads = GmailApp.search(filter, 0, 100); + + for (var x = 0; x < threads.length; x++) { + messages = threads[x].getMessages(); + + for (var i = 0; i < messages.length; i++) { + account, operation, value, date, hour, emailID = []; + + message = messages[i]; + + plainBody = message.getPlainBody(); + + if(accountRegex.test(plainBody)) { + account = RegExp.$1; + } + + if(operationRegex.test(plainBody)) { + operation = RegExp.$1; + } + + if(valueRegex.test(plainBody)) { + value = RegExp.$1; + } + + if(dateRegex.test(plainBody)) { + date = RegExp.$1; + } + + if(hourRegex.test(plainBody)) { + hour = RegExp.$1; + } + + if(emailIDRegex.test(plainBody)){ + emailID = RegExp.$1; + } + + if(paymentRegex.test(plainBody)){ + operation = RegExp.$1; + if(RegExp.$2){ + operation += ' ' + RegExp.$2 + } + date = hour = ' - '; + } + + if(account && operation && value && date && hour){ + sheet.appendRow([account, operation, value, date, hour, emailID]); + } + + // Logger.log(account); + // Logger.log(operation); + // Logger.log(value); + // Logger.log(date); + // Logger.log(hour); + } + + threads[x].addLabel(moveToLabel); + } +} diff --git a/samples/JavaScript/namespace.js b/samples/JavaScript/namespace.js new file mode 100644 index 00000000..26d9acbd --- /dev/null +++ b/samples/JavaScript/namespace.js @@ -0,0 +1,93 @@ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['lodash'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('lodash')); + } else { + root.Namespace = factory(root._); + } +})(this, function(_) { + 'use strict'; + + /** + * @module namespace + * @class namespace + */ + function Namespace() {} + + /** + * Regex for splitting keypaths into arrays. + * + * @private + * @const {RegExp} + * @type + */ + var KEYPATH_SPLITTER = /\./g; + + /** + * An internal cache to avoid calculating a keypath more than once. + * + * @private + * @type {Object} + */ + var _keypaths = {}; + + _.extend(Namespace.prototype, { + + /** + * Adds a definition to the namespace object. + * + * @public + * @instance + * @method add + * @param {String} keypath - The keypath for the definition to be added at. + * @param {Function|Object} definition - The definition to be added. + * @return {Function|Object} - The definition. + */ + add: function(keypath, definition) { + return this._walk(keypath, function(memo, name, index, keypath) { + if (index + 1 === keypath.length) { + memo[name] = _.extend(definition, memo[name]); + } + return memo[name] || (memo[name] = {}); + }); + }, + + /** + * Retrieves a definition from the namespace safely. + * + * @public + * @instance + * @method get + * @param {String} keypath - The keypath to lookup a definition for. + * @returns {Function|Object|undefined} - The definition if it exists, otherwise `undefined`. + */ + get: function(keypath) { + return this._walk(keypath); + }, + + /** + * An internal function for walking a keypath. + * + * @private + * @instance + * @method _walk + * @param {String} keypath - The keypath to walk through. + * @param {Function} [callback] - An optional callback to be called at each item in the path. + * @returns {function|Object|undefined} - The reduced keypath. + */ + _walk: function(keypath, callback) { + return _.reduce( + _keypaths[keypath] || (_keypaths[keypath] = keypath.split(KEYPATH_SPLITTER)), + callback || function(memo, name) { + return memo && memo[name]; + }, + this + ); + } + }); + + return Namespace; +}); + +//# sourceMappingURL=namespace.js.map \ No newline at end of file diff --git a/samples/LoomScript/HelloWorld.ls b/samples/LoomScript/HelloWorld.ls new file mode 100644 index 00000000..d3ba35f7 --- /dev/null +++ b/samples/LoomScript/HelloWorld.ls @@ -0,0 +1,38 @@ +package +{ + import loom.Application; + import loom2d.display.StageScaleMode; + import loom2d.ui.SimpleLabel; + + /** + The HelloWorld app renders a label with its name on it, + and traces 'hello' to the log. + */ + public class HelloWorld extends Application + { + + override public function run():void + { + stage.scaleMode = StageScaleMode.LETTERBOX; + centeredMessage(simpleLabel, this.getFullTypeName()); + + trace("hello"); + } + + // a convenience getter that generates a label and adds it to the stage + private function get simpleLabel():SimpleLabel + { + return stage.addChild(new SimpleLabel("assets/Curse-hd.fnt")) as SimpleLabel; + } + + // a utility to set the label's text and then center it on the stage + private function centeredMessage(label:SimpleLabel, msg:String):void + { + label.text = msg; + label.center(); + label.x = stage.stageWidth / 2; + label.y = (stage.stageHeight / 2) - (label.height / 2); + } + + } +} diff --git a/samples/LoomScript/SyntaxExercise.ls b/samples/LoomScript/SyntaxExercise.ls new file mode 100644 index 00000000..444ee1da --- /dev/null +++ b/samples/LoomScript/SyntaxExercise.ls @@ -0,0 +1,137 @@ +package +{ + import loom.Application; + + public interface I {} + public class C {} + public class B extends C implements I {} + final public class A extends B {} + + delegate ToCompute(s:String, o:Object):Number; + + public enum Enumeration + { + foo, + baz, + cat, + } + + struct P { + public var x:Number = 0; + public var y:Number = 0; + public static operator function =(a:P, b:P):P + { + a.x = b.x; + a.y = b.y; + + return a; + } + } + + // single-line comment + + /* + Multi-line comment + */ + + /** + Doc comment + */ + public class SyntaxExercise extends Application + { + static public var classVar:String = 'class variable'; + public const CONST:String = 'constant'; + private var _a:A = new A(); + public var _d:ToCompute; + + override public function run():void + { + trace("hello"); + } + + private function get a():A { return _a; } + private function set a(value:A):void { _a = value; } + + private function variousTypes(defaultValue:String = ''):void + { + var nil:Object = null; + var b1:Boolean = true; + var b2:Boolean = false; + var n1:Number = 0.123; + var n2:Number = 12345; + var n3:Number = 0xfed; + var s1:String = 'single-quotes with "quotes" inside'; + var s2:String = "double-quotes with 'quotes' inside"; + var f1:Function = function (life:String, universe:Object, ...everything):Number { return 42; }; + var v1:Vector. = [1, 2]; + var d1:Dictionary. = { 'three': 3, 'four': 4 }; + + _d += f1; + _d -= f1; + } + + private function variousOps():void + { + var a = ((100 + 200 - 0) / 300) % 2; + var b = 100 * 30; + var d = true && (b > 301); + var e = 0x10 | 0x01; + + b++; b--; + a += 300; a -= 5; a *= 4; a /= 2; a %= 7; + + var castable1:Boolean = (a is B); + var castable2:Boolean = (a as B) != null; + var cast:String = B(a).toString(); + var instanced:Boolean = (_a instanceof A); + } + + private function variousFlow():void + { + var n:Number = Math.random(); + if (n > 0.6) + trace('top 40!'); + else if(n > 0.3) + trace('mid 30!'); + else + trace('bottom 30'); + + var flip:String = (Math.random() > 0.5) ? 'heads' : 'tails'; + + for (var i = 0; i < 100; i++) + trace(i); + + var v:Vector. = ['a', 'b', 'c']; + for each (var s:String in v) + trace(s); + + var d:Dictionary. = { 'one': 1 }; + for (var key1:String in d) + trace(key1); + + for (var key2:Number in v) + trace(key2); + + while (i > 0) + { + i--; + if (i == 13) continue; + trace(i); + } + + do + { + i++; + } + while (i < 10); + + switch (Math.floor(Math.random()) * 3 + 1) + { + case 1 : trace('rock'); break; + case 2 : trace('paper'); break; + default: trace('scissors'); break; + } + } + + } +} diff --git a/samples/Oz/example.oz b/samples/Oz/example.oz new file mode 100644 index 00000000..21c206a2 --- /dev/null +++ b/samples/Oz/example.oz @@ -0,0 +1,52 @@ +% You can get a lot of information about Oz by following theses links : +% - http://mozart.github.io/ +% - http://en.wikipedia.org/wiki/Oz_(programming_language) +% There is also a well known book that uses Oz for pedagogical reason : +% - http://mitpress.mit.edu/books/concepts-techniques-and-models-computer-programming +% And there are two courses on edX about 'Paradigms of Computer Programming' that also uses Oz for pedagogical reason : +% - https://www.edx.org/node/2751#.VHijtfl5OSo +% - https://www.edx.org/node/4436#.VHijzfl5OSo +% +% Here is an example of some code written with Oz. + +declare +% Computes the sum of square of the N first integers. +fun {Sum N} + local SumAux in + fun {SumAux N Acc} + if N==0 then Acc + else + {Sum N-1 Acc} + end + end + {SumAux N 0} + end +end + +% Returns true if N is a prime and false otherwize +fun {Prime N} + local PrimeAcc in + fun {PrimeAcc N Acc} + if(N == 1) then false + elseif(Acc == 1) then true + else + if (N mod Acc) == 0 then false + else + {PrimeAcc N Acc-1} + end + end + end + {PrimeAcc N (N div 2)} + end +end + +% Reverse a list using cells and for loop (instead of recursivity) +fun {Reverse L} + local RevList in + RevList = {NewCell nil} + for E in L do + RevList := E|@RevList + end + @RevList + end +end diff --git a/samples/PHP/drupal.module b/samples/PHP/drupal.script! similarity index 100% rename from samples/PHP/drupal.module rename to samples/PHP/drupal.script! diff --git a/samples/Perl6/01-dash-uppercase-i.t b/samples/Perl6/01-dash-uppercase-i.t new file mode 100644 index 00000000..57a5afd0 --- /dev/null +++ b/samples/Perl6/01-dash-uppercase-i.t @@ -0,0 +1,97 @@ +use v6; + +use Test; + +=begin pod + +Test handling of -I. + +Multiple C<-I> switches are supposed to +prepend left-to-right: + + -Ifoo -Ibar + +should make C<@*INC> look like: + + foo + bar + ... + +Duplication of directories on the command line is mirrored +in the C<@*INC> variable, so C will have B +entries C in C<@*INC>. + +=end pod + +# L + +my $fragment = '-e "@*INC.perl.say"'; + +my @tests = ( + 'foo', + 'foo$bar', + 'foo bar$baz', + 'foo$foo', +); + +plan @tests*2; + +diag "Running under $*OS"; + +my ($pugs,$redir) = ($*EXECUTABLE_NAME, ">"); + +if $*OS eq any { + $pugs = 'pugs.exe'; + $redir = '>'; +}; + +sub nonce () { return (".{$*PID}." ~ (1..1000).pick) } + +sub run_pugs ($c) { + my $tempfile = "temp-ex-output" ~ nonce; + my $command = "$pugs $c $redir $tempfile"; + diag $command; + run $command; + my $res = slurp $tempfile; + unlink $tempfile; + return $res; +} + +for @tests -> $t { + my @dirs = split('$',$t); + my $command; + # This should be smarter about quoting + # (currently, this should work for WinNT and Unix shells) + $command = join " ", map { qq["-I$_"] }, @dirs; + my $got = run_pugs( $command ~ " $fragment" ); + $got .= chomp; + + if (substr($got,0,1) ~~ "[") { + # Convert from arrayref to array + $got = substr($got, 1, -1); + }; + + my @got = EVAL $got; + @got = @got[ 0..@dirs-1 ]; + my @expected = @dirs; + + is @got, @expected, "'" ~ @dirs ~ "' works"; + + $command = join " ", map { qq[-I "$_"] }, @dirs; + $got = run_pugs( $command ~ " $fragment" ); + + $got .= chomp; + if (substr($got,0,1) ~~ "[") { + # Convert from arrayref to array + $got = substr($got, 1, -1); + }; + + @got = EVAL $got; + @got = @got[ 0..@dirs-1 ]; + @expected = @dirs; + + is @got, @expected, "'" ~ @dirs ~ "' works (with a space delimiting -I)"; +} + + +# vim: ft=perl6 diff --git a/samples/Perl6/01-parse.t b/samples/Perl6/01-parse.t new file mode 100644 index 00000000..6c81fb04 --- /dev/null +++ b/samples/Perl6/01-parse.t @@ -0,0 +1,223 @@ +use v6; +BEGIN { @*INC.push('lib') }; + +use JSON::Tiny::Grammar; +use Test; + +my @t = + '{}', + '{ }', + ' { } ', + '{ "a" : "b" }', + '{ "a" : null }', + '{ "a" : true }', + '{ "a" : false }', + '{ "a" : { } }', + '[]', + '[ ]', + ' [ ] ', + # stolen from JSON::XS, 18_json_checker.t, and adapted a bit + Q<<[ + "JSON Test Pattern pass1", + {"object with 1 member":["array with 1 element"]}, + {}, + [] + ]>>, + Q<<[1]>>, + Q<<[true]>>, + Q<<[-42]>>, + Q<<[-42,true,false,null]>>, + Q<<{ "integer": 1234567890 }>>, + Q<<{ "real": -9876.543210 }>>, + Q<<{ "e": 0.123456789e-12 }>>, + Q<<{ "E": 1.234567890E+34 }>>, + Q<<{ "": 23456789012E66 }>>, + Q<<{ "zero": 0 }>>, + Q<<{ "one": 1 }>>, + Q<<{ "space": " " }>>, + Q<<{ "quote": "\""}>>, + Q<<{ "backslash": "\\"}>>, + Q<<{ "controls": "\b\f\n\r\t"}>>, + Q<<{ "slash": "/ & \/"}>>, + Q<<{ "alpha": "abcdefghijklmnopqrstuvwyz"}>>, + Q<<{ "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ"}>>, + Q<<{ "digit": "0123456789"}>>, + Q<<{ "0123456789": "digit"}>>, + Q<<{"special": "`1~!@#$%^&*()_+-={':[,]}|;.?"}>>, + Q<<{"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A"}>>, + Q<<{"true": true}>>, + Q<<{"false": false}>>, + Q<<{"null": null}>>, + Q<<{"array":[ ]}>>, + Q<<{"object":{ }}>>, + Q<<{"address": "50 St. James Street"}>>, + Q<<{"url": "http://www.JSON.org/"}>>, + Q<<{"comment": "// /* */": " "}>>, + Q<<{ " s p a c e d " :[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7]}>>, + + Q<<{"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}"}>>, + Q<<{"quotes": "" \u0022 %22 0x22 034 ""}>>, + Q<<{ "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }>>, + Q<<[ 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1 + ]>>, + Q<<[1e-1]>>, + Q<<[1e00,2e+00,2e-00,"rosebud"]>>, + Q<<[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]>>, + Q<<{ + "JSON Test Pattern pass3": { + "The outermost value": "must be an object or array.", + "In this test": "It is an object." + } +} +>>, +# from http://www.json.org/example.html + Q<<{ + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Markup Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": ["GML", "XML"] + }, + "GlossSee": "markup" + } + } + } + } +} + >>, + Q<<{"menu": { + "id": "file", + "value": "File", + "popup": { + "menuitem": [ + {"value": "New", "onclick": "CreateNewDoc()"}, + {"value": "Open", "onclick": "OpenDoc()"}, + {"value": "Close", "onclick": "CloseDoc()"} + ] + } +}}>>, + Q<<{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } +}}>>, + ; + +my @n = + '{ ', + '{ 3 : 4 }', + '{ 3 : tru }', # not quite true + '{ "a : false }', # missing quote + # stolen from JSON::XS, 18_json_checker.t + Q<<"A JSON payload should be an object or array, not a string.">>, + Q<<{"Extra value after close": true} "misplaced quoted value">>, + Q<<{"Illegal expression": 1 + 2}>>, + Q<<{"Illegal invocation": alert()}>>, + Q<<{"Numbers cannot have leading zeroes": 013}>>, + Q<<{"Numbers cannot be hex": 0x14}>>, + Q<<["Illegal backslash escape: \x15"]>>, + Q<<[\naked]>>, + Q<<["Illegal backslash escape: \017"]>>, +# skipped: wo don't implement no stinkin' aritifical limits. +# Q<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>>, + Q<<{"Missing colon" null}>>, + Q<<["Unclosed array">>, + Q<<{"Double colon":: null}>>, + Q<<{"Comma instead of colon", null}>>, + Q<<["Colon instead of comma": false]>>, + Q<<["Bad value", truth]>>, + Q<<['single quote']>>, + qq<["\ttab\tcharacter in string "]>, + Q<<["line +break"]>>, + Q<<["line\ +break"]>>, + Q<<[0e]>>, + Q<<{unquoted_key: "keys must be quoted"}>>, + Q<<[0e+]>>, + Q<<[0e+-1]>>, + Q<<{"Comma instead if closing brace": true,>>, + Q<<["mismatch"}>>, + Q<<["extra comma",]>>, + Q<<["double extra comma",,]>>, + Q<<[ , "<-- missing value"]>>, + Q<<["Comma after the close"],>>, + Q<<["Extra close"]]>>, + Q<<{"Extra comma": true,}>>, +; + +plan (+@t) + (+@n); + +my $i = 0; +for @t -> $t { + my $desc = $t; + if $desc ~~ m/\n/ { + $desc .= subst(/\n.*$/, "\\n...[$i]"); + } + my $parsed = 0; + try { + JSON::Tiny::Grammar.parse($t) + and $parsed = 1; + } + ok $parsed, "JSON string «$desc» parsed"; + $i++; +} + +for @n -> $t { + my $desc = $t; + if $desc ~~ m/\n/ { + $desc .= subst(/\n.*$/, "\\n...[$i]"); + } + my $parsed = 0; + try { JSON::Tiny::Grammar.parse($t) and $parsed = 1 }; + nok $parsed, "NOT parsed «$desc»"; + $i++; +} + + +# vim: ft=perl6 + diff --git a/samples/Perl6/A.pm b/samples/Perl6/A.pm new file mode 100644 index 00000000..345e889b --- /dev/null +++ b/samples/Perl6/A.pm @@ -0,0 +1,9 @@ +# used in t/spec/S11-modules/nested.t + +BEGIN { @*INC.push('t/spec/packages') }; + +module A::A { + use A::B; +} + +# vim: ft=perl6 diff --git a/samples/Perl6/ANSIColor.pm b/samples/Perl6/ANSIColor.pm new file mode 100644 index 00000000..87e557cb --- /dev/null +++ b/samples/Perl6/ANSIColor.pm @@ -0,0 +1,148 @@ +use v6; + +module Term::ANSIColor; + +# these will be macros one day, yet macros can't be exported so far +sub RESET is export { "\e[0m" } +sub BOLD is export { "\e[1m" } +sub UNDERLINE is export { "\e[4m" } +sub INVERSE is export { "\e[7m" } +sub BOLD_OFF is export { "\e[22m" } +sub UNDERLINE_OFF is export { "\e[24m" } +sub INVERSE_OFF is export { "\e[27m" } + +my %attrs = + reset => "0", + bold => "1", + underline => "4", + inverse => "7", + black => "30", + red => "31", + green => "32", + yellow => "33", + blue => "34", + magenta => "35", + cyan => "36", + white => "37", + default => "39", + on_black => "40", + on_red => "41", + on_green => "42", + on_yellow => "43", + on_blue => "44", + on_magenta => "45", + on_cyan => "46", + on_white => "47", + on_default => "49"; + +sub color (Str $what) is export { + my @res; + my @a = $what.split(' '); + for @a -> $attr { + if %attrs.exists($attr) { + @res.push: %attrs{$attr} + } else { + die("Invalid attribute name '$attr'") + } + } + return "\e[" ~ @res.join(';') ~ "m"; +} + +sub colored (Str $what, Str $how) is export { + color($how) ~ $what ~ color('reset'); +} + +sub colorvalid (*@a) is export { + for @a -> $el { + return False unless %attrs.exists($el) + } + return True; +} + +sub colorstrip (*@a) is export { + my @res; + for @a -> $str { + @res.push: $str.subst(/\e\[ <[0..9;]>+ m/, '', :g); + } + return @res.join; +} + +sub uncolor (Str $what) is export { + my @res; + my @list = $what.comb(/\d+/); + for @list -> $elem { + if %attrs.reverse.exists($elem) { + @res.push: %attrs.reverse{$elem} + } else { + die("Bad escape sequence: {'\e[' ~ $elem ~ 'm'}") + } + } + return @res.join(' '); +} + +=begin pod + +=head1 NAME + +Term::ANSIColor - Color screen output using ANSI escape sequences + +=head1 SYNOPSIS + + use Term::ANSIColor; + say color('bold'), "this is in bold", color('reset'); + say colored('underline red on_green', 'what a lovely colours!'); + say BOLD, 'good to be fat!', BOLD_OFF; + say 'ok' if colorvalid('magenta', 'on_black', 'inverse'); + say '\e[36m is ', uncolor('\e36m'); + say colorstrip("\e[1mThis is bold\e[0m"); + +=head1 DESCRIPTION + +Term::ANSIColor provides an interface for using colored output +in terminals. The following functions are available: + +=head2 C + +Given a string with color names, the output produced by C +sets the terminal output so the text printed after it will be colored +as specified. The following color names are recognised: + + reset bold underline inverse black red green yellow blue + magenta cyan white default on_black on_red on_green on_yellow + on_blue on_magenta on_cyan on_white on_default + +The on_* family of colors correspond to the background colors. + +=head2 C + +C is similar to C. It takes two Str arguments, +where the first is the colors to be used, and the second is the string +to be colored. The C sequence is automagically placed after +the string. + +=head2 C + +C gets an array of color specifications (like those +passed to C) and returns true if all of them are valid, +false otherwise. + +=head2 C + +C, given a string, removes all the escape sequences +in it, leaving the plain text without effects. + +=head2 C + +Given escape sequences, C returns a string with readable +color names. E.g. passing "\e[36;44m" will result in "cyan on_blue". + +=head1 Constants + +C provides constants which are just strings of +appropriate escape sequences. The following constants are available: + + RESET BOLD UNDERLINE INVERSE BOLD_OFF UNDERLINE_OFF INVERSE_OFF + +=end pod + +# vim: ft=perl6 diff --git a/samples/Perl6/Bailador.pm b/samples/Perl6/Bailador.pm new file mode 100644 index 00000000..96e4d8d1 --- /dev/null +++ b/samples/Perl6/Bailador.pm @@ -0,0 +1,102 @@ +use Bailador::App; +use Bailador::Request; +use Bailador::Response; +use Bailador::Context; +use HTTP::Easy::PSGI; + +module Bailador; + +my $app = Bailador::App.current; + +our sub import { + my $file = callframe(1).file; + my $slash = $file.rindex('/'); + if $slash { + $app.location = $file.substr(0, $file.rindex('/')); + } else { + $app.location = '.'; + } +} + +sub route_to_regex($route) { + $route.split('/').map({ + my $r = $_; + if $_.substr(0, 1) eq ':' { + $r = q{(<-[\/\.]>+)}; + } + $r + }).join("'/'"); +} + +multi parse_route(Str $route) { + my $r = route_to_regex($route); + return "/ ^ $r \$ /".eval; +} + +multi parse_route($route) { + # do nothing + $route +} + +sub get(Pair $x) is export { + my $p = parse_route($x.key) => $x.value; + $app.add_route: 'GET', $p; + return $x; +} + +sub post(Pair $x) is export { + my $p = parse_route($x.key) => $x.value; + $app.add_route: 'POST', $p; + return $x; +} + +sub request is export { $app.context.request } + +sub content_type(Str $type) is export { + $app.response.headers = $type; +} + +sub header(Str $name, Cool $value) is export { + $app.response.headers{$name} = ~$value; +} + +sub status(Int $code) is export { + $app.response.code = $code; +} + +sub template(Str $tmpl, *@params) is export { + $app.template($tmpl, @params); +} + +our sub dispatch_request(Bailador::Request $r) { + return dispatch($r.env); +} + +sub dispatch($env) { + $app.context.env = $env; + + my ($r, $match) = $app.find_route($env); + + if $r { + status 200; + if $match { + $app.response.content = $r.value.(|$match.list); + } else { + $app.response.content = $r.value.(); + } + } + + return $app.response; +} + +sub dispatch-psgi($env) { + return dispatch($env).psgi; +} + +sub baile is export { + given HTTP::Easy::PSGI.new(port => 3000) { + .app(&dispatch-psgi); + say "Entering the development dance floor: http://0.0.0.0:3000"; + .run; + } +} diff --git a/samples/Perl6/ContainsUnicode.pm b/samples/Perl6/ContainsUnicode.pm new file mode 100644 index 00000000..1f3c25c7 --- /dev/null +++ b/samples/Perl6/ContainsUnicode.pm @@ -0,0 +1,7 @@ +module ContainsUnicode { + sub uc-and-join(*@things, :$separator = ', ') is export { + @things».uc.join($separator) + } +} + +# vim: ft=perl6 diff --git a/samples/Perl6/Exception.pm b/samples/Perl6/Exception.pm new file mode 100644 index 00000000..480a8af9 --- /dev/null +++ b/samples/Perl6/Exception.pm @@ -0,0 +1,1431 @@ +my class Failure { ... } +my role X::Comp { ... } +my class X::ControlFlow { ... } + +my class Exception { + has $!ex; + + method backtrace() { Backtrace.new(self) } + + multi method Str(Exception:D:) { + self.?message.Str // 'Something went wrong' + } + + multi method gist(Exception:D:) { + my $str = try self.?message; + return "Error while creating error string: $!" if $!; + $str ~= "\n"; + try $str ~= self.backtrace; + return "$str\nError while creating backtrace: $!.message()\n$!.backtrace.full();" if $!; + return $str; + } + + method throw() is hidden_from_backtrace { + nqp::bindattr(self, Exception, '$!ex', nqp::newexception()) + unless nqp::isconcrete($!ex); + nqp::setpayload($!ex, nqp::decont(self)); + my $msg := self.?message; + nqp::setmessage($!ex, nqp::unbox_s($msg.Str)) + if $msg.defined; + nqp::throw($!ex) + } + method rethrow() is hidden_from_backtrace { + nqp::setpayload($!ex, nqp::decont(self)); + nqp::rethrow($!ex) + } + + method resumable() { + nqp::p6bool(nqp::istrue(nqp::atkey($!ex, 'resume'))); + } + + method resume() { + my Mu $resume := nqp::atkey($!ex, 'resume'); + if $resume { + $resume(); + } + else { + die "Exception is not resumable"; + } + } + + method fail(Exception:D:) { + try self.throw; + my $fail := Failure.new($!); + my Mu $return := nqp::getlexcaller('RETURN'); + $return($fail) unless nqp::isnull($return); + $fail + } + + method is-compile-time { False } +} + +my class X::AdHoc is Exception { + has $.payload; + method message() { $.payload.Str } + method Numeric() { $.payload.Numeric } +} + +my class X::Method::NotFound is Exception { + has $.method; + has $.typename; + has Bool $.private = False; + method message() { + $.private + ?? "No such private method '$.method' for invocant of type '$.typename'" + !! "No such method '$.method' for invocant of type '$.typename'"; + } +} + +my class X::Method::InvalidQualifier is Exception { + has $.method; + has $.invocant; + has $.qualifier-type; + method message() { + "Cannot dispatch to method $.method on {$.qualifier-type.^name} " + ~ "because it is not inherited or done by {$.invocant.^name}"; + } +} + + +sub EXCEPTION(|) { + my Mu $vm_ex := nqp::shift(nqp::p6argvmarray()); + my Mu $payload := nqp::getpayload($vm_ex); + if nqp::p6bool(nqp::istype($payload, Exception)) { + nqp::bindattr($payload, Exception, '$!ex', $vm_ex); + $payload; + } else { + my int $type = nqp::getextype($vm_ex); + my $ex; +#?if parrot + if $type == pir::const::EXCEPTION_METHOD_NOT_FOUND && +#?endif +#?if !parrot + if +#?endif + nqp::p6box_s(nqp::getmessage($vm_ex)) ~~ /"Method '" (.*?) "' not found for invocant of class '" (.+)\'$/ { + + $ex := X::Method::NotFound.new( + method => ~$0, + typename => ~$1, + ); + } + else { + + $ex := nqp::create(X::AdHoc); + nqp::bindattr($ex, X::AdHoc, '$!payload', nqp::p6box_s(nqp::getmessage($vm_ex))); + } + nqp::bindattr($ex, Exception, '$!ex', $vm_ex); + $ex; + } +} + +my class X::Comp::AdHoc { ... } +sub COMP_EXCEPTION(|) { + my Mu $vm_ex := nqp::shift(nqp::p6argvmarray()); + my Mu $payload := nqp::getpayload($vm_ex); + if nqp::p6bool(nqp::istype($payload, Exception)) { + nqp::bindattr($payload, Exception, '$!ex', $vm_ex); + $payload; + } else { + my $ex := nqp::create(X::Comp::AdHoc); + nqp::bindattr($ex, Exception, '$!ex', $vm_ex); + nqp::bindattr($ex, X::AdHoc, '$!payload', nqp::p6box_s(nqp::getmessage($vm_ex))); + $ex; + } +} + + +do { + sub is_runtime($bt) { + for $bt.keys { + try { + my Mu $sub := nqp::getattr(nqp::decont($bt[$_]), ForeignCode, '$!do'); + my Mu $codeobj := nqp::ifnull(nqp::getcodeobj($sub), Mu); + my $is_nqp = $codeobj && $codeobj.HOW.name($codeobj) eq 'NQPRoutine'; + return True if nqp::iseq_s(nqp::getcodename($sub), 'eval') && $is_nqp; + return False if nqp::iseq_s(nqp::getcodename($sub), 'compile') && $is_nqp; + } + } + return False; + } + + + sub print_exception(|) is hidden_from_backtrace { + my Mu $ex := nqp::atpos(nqp::p6argvmarray(), 0); + try { + my $e := EXCEPTION($ex); + my Mu $err := nqp::getstderr(); + +#?if parrot + if $e.is-compile-time || is_runtime($ex.backtrace) { +#?endif +#?if !parrot + if $e.is-compile-time || is_runtime(nqp::backtrace($ex)) { +#?endif + nqp::printfh($err, $e.gist); + nqp::printfh($err, "\n"); + } + else { + nqp::printfh($err, "===SORRY!===\n"); + nqp::printfh($err, $e.Str); + nqp::printfh($err, "\n"); + } + $_() for nqp::hllize(nqp::getcurhllsym('@END_PHASERS')); + } + if $! { +#?if parrot + pir::perl6_based_rethrow__0PP(nqp::getattr(nqp::decont($!), Exception, '$!ex'), $ex); +#?endif +#?if !parrot + nqp::rethrow(nqp::getattr(nqp::decont($!), Exception, '$!ex')); + $ex +#?endif + } + } + + sub print_control(|) is hidden_from_backtrace { + my Mu $ex := nqp::atpos(nqp::p6argvmarray(), 0); + my int $type = nqp::getextype($ex); + if ($type == nqp::const::CONTROL_WARN) { + my Mu $err := nqp::getstderr(); + my $msg = nqp::p6box_s(nqp::getmessage($ex)); + nqp::printfh($err, $msg ?? "$msg" !! "Warning"); +#?if parrot + nqp::printfh($err, Backtrace.new($ex.backtrace, 0).nice(:oneline)); +#?endif +#?if jvm +# XXX Backtraces busted +# nqp::printfh($err, Backtrace.new(nqp::backtrace($ex), 0).nice(:oneline)); +#?endif + nqp::printfh($err, "\n"); +#?if parrot + my $resume := nqp::atkey($ex, 'resume'); + if ($resume) { + $resume(); + } +#?endif +#?if !parrot + nqp::resume($ex) +#?endif + } + if ($type == nqp::const::CONTROL_LAST) { + X::ControlFlow.new(illegal => 'last', enclosing => 'loop construct').throw; + } + if ($type == nqp::const::CONTROL_NEXT) { + X::ControlFlow.new(illegal => 'next', enclosing => 'loop construct').throw; + } + if ($type == nqp::const::CONTROL_REDO) { + X::ControlFlow.new(illegal => 'redo', enclosing => 'loop construct').throw; + } + if ($type == nqp::const::CONTROL_PROCEED) { + X::ControlFlow.new(illegal => 'proceed', enclosing => 'when clause').throw; + } + if ($type == nqp::const::CONTROL_SUCCEED) { + # XXX: should work like leave() ? + X::ControlFlow.new(illegal => 'succeed', enclosing => 'when clause').throw; + } + if ($type == nqp::const::CONTROL_TAKE) { + X::ControlFlow.new(illegal => 'take', enclosing => 'gather').throw; + } + } + + my Mu $comp := nqp::getcomp('perl6'); + $comp.HOW.add_method($comp, 'handle-exception', + method (|) { + my Mu $ex := nqp::atpos(nqp::p6argvmarray(), 1); +#?if parrot + pir::perl6_invoke_catchhandler__vPP(&print_exception, $ex); +#?endif +#?if !parrot + print_exception($ex); +#?endif + nqp::exit(1); + 0; + } + ); + $comp.HOW.add_method($comp, 'handle-control', + method (|) { + my Mu $ex := nqp::atpos(nqp::p6argvmarray(), 1); +#?if parrot + pir::perl6_invoke_catchhandler__vPP(&print_control, $ex); +#?endif +#?if !parrot + print_control($ex); +#?endif + nqp::rethrow($ex); + } + ); + +} + +my role X::OS { + has $.os-error; +} + +my role X::IO does X::OS { }; + +my class X::IO::Rename does X::IO is Exception { + has $.from; + has $.to; + method message() { + "Failed to rename '$.from' to '$.to': $.os-error" + } +} + +my class X::IO::Copy does X::IO is Exception { + has $.from; + has $.to; + method message() { + "Failed to copy '$.from' to '$.to': $.os-error" + } +} + +my class X::IO::Symlink does X::IO is Exception { + has $.target; + has $.name; + method message() { + "Failed to create symlink called '$.name' on target '$.target': $.os-error" + } +} + +my class X::IO::Link does X::IO is Exception { + has $.target; + has $.name; + method message() { + "Failed to create link called '$.name' on target '$.target': $.os-error" + } +} + +my class X::IO::Mkdir does X::IO is Exception { + has $.path; + has $.mode; + method message() { + "Failed to create directory '$.path' with mode '0o{$.mode.fmt("%03o")}': $.os-error" + } +} + +my class X::IO::Chdir does X::IO is Exception { + has $.path; + method message() { + "Failed to change the working directory to '$.path': $.os-error" + } +} + +my class X::IO::Dir does X::IO is Exception { + has $.path; + method message() { + "Failed to get the directory contents of '$.path': $.os-error" + } +} + +my class X::IO::Cwd does X::IO is Exception { + method message() { + "Failed to get the working directory: $.os-error" + } +} + +my class X::IO::Rmdir does X::IO is Exception { + has $.path; + method message() { + "Failed to remove the directory '$.path': $.os-error" + } +} + +my class X::IO::Unlink does X::IO is Exception { + has $.path; + method message() { + "Failed to remove the file '$.path': $.os-error" + } +} + +my class X::IO::Chmod does X::IO is Exception { + has $.path; + has $.mode; + method message() { + "Failed to set the mode of '$.path' to '0o{$.mode.fmt("%03o")}': $.os-error" + } +} + +my role X::Comp is Exception { + has $.filename; + has $.line; + has $.column; + has @.modules; + has $.is-compile-time = False; + has $.pre; + has $.post; + has @.highexpect; + multi method gist(::?CLASS:D: :$sorry = True, :$expect = True) { + if $.is-compile-time { + my $color = %*ENV // $*OS ne 'MSWin32'; + my ($red, $green, $yellow, $clear) = $color + ?? ("\e[31m", "\e[32m", "\e[33m", "\e[0m") + !! ("", "", "", ""); + my $eject = $*OS eq 'MSWin32' ?? "" !! "\x[23CF]"; + my $r = $sorry ?? self.sorry_heading() !! ""; + $r ~= "$.message\nat $.filename():$.line\n------> "; + $r ~= "$green$.pre$yellow$eject$red$.post$clear" if defined $.pre; + if $expect && @.highexpect { + $r ~= "\n expecting any of:"; + for @.highexpect { + $r ~= "\n $_"; + } + } + for @.modules.reverse[1..*] { + $r ~= $_.defined + ?? "\n from module $_ ($_:$_)" + !! "\n from $_:$_"; + } + $r; + } + else { + self.Exception::gist; + } + } + method sorry_heading() { + my $color = %*ENV // $*OS ne 'MSWin32'; + my ($red, $clear) = $color ?? ("\e[31m", "\e[0m") !! ("", ""); + "$red==={$clear}SORRY!$red===$clear Error while compiling $.filename\n" + } + method SET_FILE_LINE($file, $line) { + $!filename = $file; + $!line = $line; + $!is-compile-time = True; + } +} + +my class X::Comp::Group is Exception { + has $.panic; + has @.sorrows; + has @.worries; + + method is-compile-time() { True } + + multi method gist(::?CLASS:D:) { + my $r = ""; + if $.panic || @.sorrows { + my $color = %*ENV // $*OS ne 'MSWin32'; + my ($red, $clear) = $color ?? ("\e[31m", "\e[0m") !! ("", ""); + $r ~= "$red==={$clear}SORRY!$red===$clear\n"; + for @.sorrows { + $r ~= .gist(:!sorry, :!expect) ~ "\n"; + } + if $.panic { + $r ~= $.panic.gist(:!sorry) ~ "\n"; + } + } + if @.worries { + $r ~= $.panic || @.sorrows + ?? "Other potential difficulties:\n" + !! "Potential difficulties:\n"; + for @.worries { + $r ~= .gist(:!sorry, :!expect).indent(4) ~ "\n"; + } + } + $r + } + + method message() { + my @m; + for @.sorrows { + @m.push(.message); + } + if $.panic { + @m.push($.panic.message); + } + for @.worries { + @m.push(.message); + } + @m.join("\n") + } +} + +# XXX a hack for getting line numbers from exceptions from the metamodel +my class X::Comp::AdHoc is X::AdHoc does X::Comp { + method is-compile-time() { True } +} + +my role X::Syntax does X::Comp { } +my role X::Pod { } + +my class X::NYI is Exception { + has $.feature; + method message() { "$.feature not yet implemented. Sorry. " } +} +my class X::Comp::NYI is X::NYI does X::Comp { }; + +my class X::Trait::Unknown is Exception { + has $.type; # is, will, of etc. + has $.subtype; # wrong subtype being tried + has $.declaring; # variable, sub, parameter, etc. + method message () { + "Can't use unknown trait '$.type $.subtype' in a$.declaring declaration." + } +} +my class X::Comp::Trait::Unknown is X::Trait::Unknown does X::Comp { }; + +my class X::Trait::NotOnNative is Exception { + has $.type; # is, will, of etc. + has $.subtype; # wrong subtype being tried + has $.native; # type of native (optional) + method message () { + "Can't use trait '$.type $.subtype' on a native" + ~ ( $.native ?? " $.native." !! "." ); + } +} +my class X::Comp::Trait::NotOnNative is X::Trait::NotOnNative does X::Comp { }; + +my class X::OutOfRange is Exception { + has $.what = 'Argument'; + has $.got = ''; + has $.range = ''; + has $.comment; + method message() { + $.comment.defined + ?? "$.what out of range. Is: $.got, should be in $.range.gist(); $.comment" + !! "$.what out of range. Is: $.got, should be in $.range.gist()" + } +} + +my class X::Buf::AsStr is Exception { + has $.method; + method message() { + "Cannot use a Buf as a string, but you called the $.method method on it"; + } +} +my class X::Buf::Pack is Exception { + has $.directive; + method message() { + "Unrecognized directive '$.directive'"; + } +} + +my class X::Buf::Pack::NonASCII is Exception { + has $.char; + method message() { + "non-ASCII character '$.char' while processing an 'A' template in pack"; + } +} + +my class X::Signature::Placeholder does X::Comp { + has $.placeholder; + method message() { + "Placeholder variable '$.placeholder' cannot override existing signature"; + } +} + +my class X::Placeholder::Block does X::Comp { + has $.placeholder; + method message() { + "Placeholder variable $.placeholder may not be used here because the surrounding block takes no signature"; + } +} + +my class X::Placeholder::Mainline is X::Placeholder::Block { + method message() { + "Cannot use placeholder parameter $.placeholder in the mainline" + } +} + +my class X::Undeclared does X::Comp { + has $.what = 'Variable'; + has $.symbol; + has @.suggestions; + method message() { + my $message := "$.what '$.symbol' is not declared"; + if +@.suggestions == 1 { + $message := "$message. Did you mean '@.suggestions[0]'?"; + } elsif +@.suggestions > 1 { + $message := "$message. Did you mean any of these?\n { @.suggestions.join("\n ") }\n"; + } + $message; + } +} + +my class X::Attribute::Undeclared is X::Undeclared { + has $.package-kind; + has $.package-name; + + method message() { + "Attribute $.symbol not declared in $.package-kind $.package-name"; + } +} + +my class X::Undeclared::Symbols does X::Comp { + has %.post_types; + has %.unk_types; + has %.unk_routines; + has %.routine_suggestion; + has %.type_suggestion; + multi method gist(:$sorry = True) { + ($sorry ?? self.sorry_heading() !! "") ~ self.message + } + method message() { + sub l(@l) { + my @lu = @l.map({ nqp::hllize($_) }).uniq.sort; + 'used at line' ~ (@lu == 1 ?? ' ' !! 's ') ~ @lu.join(', ') + } + sub s(@s) { + "Did you mean '{ @s.join("', '") }'?"; + } + my $r = ""; + if %.post_types { + $r ~= "Illegally post-declared type" ~ (%.post_types.elems == 1 ?? "" !! "s") ~ ":\n"; + for %.post_types.sort(*.key) { + $r ~= " $_.key() &l($_.value)\n"; + } + } + if %.unk_types { + $r ~= "Undeclared name" ~ (%.unk_types.elems == 1 ?? "" !! "s") ~ ":\n"; + for %.unk_types.sort(*.key) { + $r ~= " $_.key() &l($_.value)"; + if +%.type_suggestion{$_.key()} { + $r ~= ". " ~ s(%.type_suggestion{$_.key()}); + } + $r ~= "\n"; + } + } + if %.unk_routines { + $r ~= "Undeclared routine" ~ (%.unk_routines.elems == 1 ?? "" !! "s") ~ ":\n"; + for %.unk_routines.sort(*.key) { + $r ~= " $_.key() &l($_.value)"; + if +%.routine_suggestion{$_.key()} { + $r ~= ". " ~ s(%.routine_suggestion{$_.key()}); + } + $r ~= "\n"; + } + } + $r + } +} + +my class X::Redeclaration does X::Comp { + has $.symbol; + has $.postfix = ''; + has $.what = 'symbol'; + method message() { + "Redeclaration of $.what $.symbol$.postfix"; + } +} + +my class X::Redeclaration::Outer does X::Comp { + has $.symbol; + method message() { + "Lexical symbol '$.symbol' is already bound to an outer symbol;\n" ~ + "the implicit outer binding must be rewritten as OUTER::<$.symbol>\n" ~ + "before you can unambiguously declare a new '$.symbol' in this scope"; + } +} + +my class X::Import::Redeclaration does X::Comp { + has @.symbols; + has $.source-package-name; + method message() { + @.symbols == 1 + ?? "Cannot import symbol @.symbols[0] from $.source-package-name, because it already exists in this lexical scope" + !! ("Cannot import the following symbols from $.source-package-name, because they already exist in this lexical scope: ", @.symbols.join(', ')); + } +} + +my class X::Import::OnlystarProto does X::Comp { + has @.symbols; + has $.source-package-name; + method message() { + @.symbols == 1 + ?? "Cannot import symbol @.symbols[0] from $.source-package-name, only onlystar-protos can be merged" + !! ("Cannot import the following symbols from $.source-package-name, only onlystar-protos can be merged: ", @.symbols.join(', ')); + } +} + +my class X::Phaser::Multiple does X::Comp { + has $.block; + method message() { "Only one $.block block is allowed" } +} + +my class X::Obsolete does X::Comp { + has $.old; + has $.replacement; # can't call it $.new, collides with constructor + has $.when = 'in Perl 6'; + method message() { "Unsupported use of $.old; $.when please use $.replacement" } +} + +my class X::Parameter::Default does X::Comp { + has $.how; + has $.parameter; + method message() { + $.parameter + ?? "Cannot put default on $.how parameter $.parameter" + !! "Cannot put default on anonymous $.how parameter"; + } +} + +my class X::Parameter::Placeholder does X::Comp { + has $.parameter; + has $.right; + method message() { + "In signature parameter, placeholder variables like $.parameter are illegal\n" + ~ "you probably meant a named parameter: '$.right'"; + } +} + +my class X::Parameter::Twigil does X::Comp { + has $.parameter; + has $.twigil; + method message() { + "In signature parameter $.parameter, it is illegal to use the $.twigil twigil"; + } +} + +my class X::Parameter::MultipleTypeConstraints does X::Comp { + has $.parameter; + method message() { + ($.parameter ?? "Parameter $.parameter" !! 'A parameter') + ~ " may only have one prefix type constraint"; + } +} + +my class X::Parameter::WrongOrder does X::Comp { + has $.misplaced; + has $.parameter; + has $.after; + method message() { + "Cannot put $.misplaced parameter $.parameter after $.after parameters"; + } +} + +my class X::Parameter::InvalidType does X::Comp { + has $.typename; + has @.suggestions; + method message() { + my $msg := "Invalid typename '$.typename' in parameter declaration."; + if +@.suggestions > 0 { + $msg := $msg ~ " Did you mean '" ~ @.suggestions.join("', '") ~ "'?"; + } + return $msg; + } +} + +my class X::Signature::NameClash does X::Comp { + has $.name; + method message() { + "Name $.name used for more than one named parameter"; + } +} + +my class X::Method::Private::Permission does X::Comp { + has $.method; + has $.source-package; + has $.calling-package; + method message() { + "Cannot call private method '$.method' on package $.source-package because it does not trust $.calling-package"; + } +} + +my class X::Method::Private::Unqualified does X::Comp { + has $.method; + method message() { + "Private method call to $.method must be fully qualified with the package containing the method"; + } +} + +my class X::Bind is Exception { + has $.target; + method message() { + $.target.defined + ?? "Cannot bind to $.target" + !! 'Cannot use bind operator with this left-hand side' + } +} +my class X::Bind::NativeType does X::Comp { + has $.name; + method message() { + "Cannot bind to natively typed variable '$.name'; use assignment instead" + } +} +my class X::Bind::Slice is Exception { + has $.type; + method message() { + "Cannot bind to {$.type.^name} slice"; + } +} +my class X::Bind::ZenSlice is X::Bind::Slice { + method message() { + "Cannot bind to {$.type.^name} zen slice"; + } +} + +my class X::Value::Dynamic does X::Comp { + has $.what; + method message() { "$.what value must be known at compile time" } +} + +my class X::Syntax::Name::Null does X::Syntax { + method message() { 'Name component may not be null'; } +} + +my class X::Syntax::UnlessElse does X::Syntax { + method message() { '"unless" does not take "else", please rewrite using "if"' } +} + +my class X::Syntax::KeywordAsFunction does X::Syntax { + has $.word; + has $.needparens; + method message { + "Word '$.word' interpreted as '{$.word}()' function call; please use whitespace " + ~ ($.needparens ?? 'around the parens' !! 'instead of parens') + } +} + +my class X::Syntax::Malformed::Elsif does X::Syntax { + has $.what = 'else if'; + method message() { qq{In Perl 6, please use "elsif' instead of "$.what"} } +} + +my class X::Syntax::Reserved does X::Syntax { + has $.reserved; + has $.instead = ''; + method message() { "The $.reserved is reserved$.instead" } +} + +my class X::Syntax::P5 does X::Syntax { + method message() { 'This appears to be Perl 5 code' } +} + +my class X::Syntax::NegatedPair does X::Syntax { + has $.key; + method message() { "Argument not allowed on negated pair with key '$.key'" } +} + +my class X::Syntax::Variable::Numeric does X::Syntax { + has $.what = 'variable'; + method message() { "Cannot declare a numeric $.what" } +} + +my class X::Syntax::Variable::Match does X::Syntax { + method message() { 'Cannot declare a match variable' } +} + +my class X::Syntax::Variable::Twigil does X::Syntax { + has $.twigil; + has $.scope; + method message() { "Cannot use $.twigil twigil on $.scope variable" } +} + +my class X::Syntax::Variable::IndirectDeclaration does X::Syntax { + method message() { 'Cannot declare a variable by indirect name (use a hash instead?)' } +} + +my class X::Syntax::Augment::WithoutMonkeyTyping does X::Syntax { + method message() { "augment not allowed without 'use MONKEY_TYPING'" }; +} + +my class X::Syntax::Augment::Illegal does X::Syntax { + has $.package; + method message() { "Cannot augment $.package because it is closed" }; +} + +my class X::Syntax::Argument::MOPMacro does X::Syntax { + has $.macro; + method message() { "Cannot give arguments to $.macro" }; +} + +my class X::Does::TypeObject is Exception { + method message() { "Cannot use 'does' operator with a type object." } +} + +my class X::Role::Initialization is Exception { + has $.role; + method message() { "Can only supply an initialization value for a role if it has a single public attribute, but this is not the case for '{$.role.^name}'" } +} + +my class X::Syntax::Comment::Embedded does X::Syntax { + method message() { "Opening bracket required for #` comment" } +} + +my class X::Syntax::Pod::BeginWithoutIdentifier does X::Syntax does X::Pod { + method message() { + '=begin must be followed by an identifier; (did you mean "=begin pod"?)' + } +} + +my class X::Syntax::Pod::BeginWithoutEnd does X::Syntax does X::Pod { + method message() { '=begin without matching =end' } +} + +my class X::Syntax::Confused does X::Syntax { + has $.reason = 'unknown'; + method message() { $.reason eq 'unknown' ?? 'Confused' !! $.reason } +} + +my class X::Syntax::Malformed does X::Syntax { + has $.what; + method message() { "Malformed $.what" } +} +my class X::Syntax::Missing does X::Syntax { + has $.what; + method message() { "Missing $.what" } +} + +my class X::Syntax::Perl5Var does X::Syntax { + has $.name; + my %m = + '$*' => '^^ and $$', + '$"' => '.join() method', + '$$' => '$*PID', + '$(' => '$*GID', + '$)' => '$*EGID', + '$<' => '$*UID', + '$>' => '$*EUID', + '$;' => 'real multidimensional hashes', + '$&' => '$<>', + '$`' => 'explicit pattern before <(', + '$\'' => 'explicit pattern after )>', + '$,' => '$*OUT.output_field_separator()', + '$.' => "the filehandle's .line method", + '$\\' => "the filehandle's .ors attribute", + '$|' => ':autoflush on open', + '$?' => '$! for handling child errors also', + '$@' => '$!', + '$#' => '.fmt', + '$[' => 'user-defined array indices', + '$]' => '$*PERL_VERSION', + + '$^C' => 'COMPILING namespace', + '$^D' => '$*DEBUGGING', + '$^E' => '$!.extended_os_error', + '$^F' => '$*SYSTEM_FD_MAX', + '$^H' => '$?FOO variables', + '$^I' => '$*INPLACE', + '$^M' => 'a global form such as $*M', + '$^N' => '$/[*-1]', + '$^O' => '$?OS or $*OS', + '$^R' => 'an explicit result variable', + '$^S' => 'context function', + '$^T' => '$*BASETIME', + '$^V' => '$*PERL_VERSION', + '$^W' => '$*WARNING', + '$^X' => '$*EXECUTABLE_NAME', + + '$:' => 'Form module', + '$-' => 'Form module', + '$+' => 'Form module', + '$=' => 'Form module', + '$%' => 'Form module', + '$^' => 'Form module', + '$~' => 'Form module', + '$^A' => 'Form module', + '$^L' => 'Form module', + + '@-' => '.from method', + '@+' => '.to method', + + '%-' => '.from method', + '%+' => '.to method', + '%^H' => '$?FOO variables', + ; + method message() { + my $v = $.name ~~ m/ <[ $ @ % & ]> [ \^ <[ A..Z ]> | \W ] /; + $v + ?? %m{~$v} + ?? "Unsupported use of $v variable; in Perl 6 please use {%m{~$v}}" + !! "Unsupported use of $v variable" + !! 'Non-declarative sigil is missing its name'; + } +} + +my class X::Syntax::Self::WithoutObject does X::Syntax { + method message() { "'self' used where no object is available" } +} +my class X::Syntax::VirtualCall does X::Syntax { + has $.call; + method message() { "Virtual call $.call may not be used on partially constructed objects" } +} +my class X::Syntax::NoSelf does X::Syntax { + has $.variable; + method message() { "Variable $.variable used where no 'self' is available" } +} + +my class X::Syntax::Number::RadixOutOfRange does X::Syntax { + has $.radix; + method message() { "Radix $.radix out of range (allowed: 2..36)" } +} + +my class X::Syntax::NonAssociative does X::Syntax { + has $.left; + has $.right; + method message() { + "Operators '$.left' and '$.right' are non-associative and require parenthesis"; + } +} + +my class X::Syntax::Regex::Adverb does X::Syntax { + has $.adverb; + has $.construct; + method message() { "Adverb $.adverb not allowed on $.construct" } +} + +my class X::Syntax::Regex::UnrecognizedMetachar does X::Syntax { + has $.metachar; + method message() { "Unrecognized regex metacharacter $.metachar (must be quoted to match literally)" } +} + +my class X::Syntax::Regex::NullRegex does X::Syntax { + method message() { 'Null regex not allowed' } +} + +my class X::Syntax::Signature::InvocantMarker does X::Syntax { + method message() { + "Can only use : as invocant marker in a signature after the first parameter" + } +} + +my class X::Syntax::Extension::Category does X::Syntax { + has $.category; + method message() { + "Cannot add tokens of category '$.category'"; + } +} + +my class X::Syntax::Extension::Null does X::Syntax { + method message() { + "Null operator is not allowed"; + } +} + +my class X::Syntax::InfixInTermPosition does X::Syntax { + has $.infix; + method message() { + "Preceding context expects a term, but found infix $.infix instead"; + } +} + +my class X::Attribute::Package does X::Comp { + has $.package-kind; + has $.name; + method message() { "A $.package-kind cannot have attributes, but you tried to declare '$.name'" } +} +my class X::Attribute::NoPackage does X::Comp { + has $.name; + method message() { "You cannot declare attribute '$.name' here; maybe you'd like a class or a role?" } +} +my class X::Declaration::Scope does X::Comp { + has $.scope; + has $.declaration; + method message() { "Cannot use '$.scope' with $.declaration declaration" } +} + +my class X::Declaration::Scope::Multi is X::Declaration::Scope { + method message() { + "Cannot use '$.scope' with individual multi candidates. Please declare an {$.scope}-scoped proto instead"; + } +} + +my class X::Anon::Multi does X::Comp { + has $.multiness; + has $.routine-type = 'routine'; + method message() { "Cannot put $.multiness on anonymous $.routine-type" } +} +my class X::Anon::Augment does X::Comp { + has $.package-kind; + method message() { "Cannot augment anonymous $.package-kind" } +} +my class X::Augment::NoSuchType does X::Comp { + has $.package-kind; + has $.package; + method message() { "You tried to augment $.package-kind $.package, but it does not exist" } +} + +my class X::Routine::Unwrap is Exception { + method message() { "Cannot unwrap routine: invalid wrap handle" } +} + +my class X::Constructor::Positional is Exception { + has $.type; + method message() { "Default constructor for '" ~ $.type.^name ~ "' only takes named arguments" } +} + +my class X::Hash::Store::OddNumber is Exception { + method message() { "Odd number of elements found where hash expected" } +} + +my class X::Package::Stubbed does X::Comp { + has @.packages; + # TODO: suppress display of line number + method message() { + "The following packages were stubbed but not defined:\n " + ~ @.packages.join("\n "); + } +} + +my class X::Phaser::PrePost is Exception { + has $.phaser = 'PRE'; + has $.condition; + method message { + my $what = $.phaser eq 'PRE' ?? 'Precondition' !! 'Postcondition'; + $.condition.defined + ?? "$what '$.condition.trim()' failed" + !! "$what failed"; + } +} + +my class X::Str::Numeric is Exception { + has $.source; + has $.pos; + has $.reason; + method source-indicator { + constant marker = chr(0x23CF); + join '', "in '", + $.source.substr(0, $.pos), + marker, + $.source.substr($.pos), + "' (indicated by ", + marker, + ")", + ; + } + method message() { + "Cannot convert string to number: $.reason $.source-indicator"; + } +} + +my class X::Str::Match::x is Exception { + has $.got; + method message() { + "in Str.match, got invalid value of type {$.got.^name} for :x, must be Int or Range" + } +} + +my class X::Str::Trans::IllegalKey is Exception { + has $.key; + method message { + "in Str.trans, got illegal substitution key of type {$.key.^name} (should be a Regex or Str)" + } +} +my class X::Str::Trans::InvalidArg is Exception { + has $.got; + method message() { + "Only Pair objects are allowed as arguments to Str.trans, got {$.got.^name}"; + } +} + +my class X::Range::InvalidArg is Exception { + has $.got; + method message() { + "{$.got.^name} objects are not valid endpoints for Ranges"; + } +} + +my class X::Sequence::Deduction is Exception { + method message() { 'Unable to deduce sequence' } +} + +my class X::Backslash::UnrecognizedSequence does X::Syntax { + has $.sequence; + method message() { "Unrecognized backslash sequence: '\\$.sequence'" } +} + +my class X::Backslash::NonVariableDollar does X::Syntax { + method message() { "Non-variable \$ must be backslashed" } +} + +my class X::ControlFlow is Exception { + has $.illegal; # something like 'next' + has $.enclosing; # .... outside a loop + + method message() { "$.illegal without $.enclosing" } +} +my class X::ControlFlow::Return is X::ControlFlow { + method illegal() { 'return' } + method enclosing() { 'Routine' } + method message() { 'Attempt to return outside of any Routine' } +} + +my class X::Composition::NotComposable does X::Comp { + has $.target-name; + has $.composer; + method message() { + $.composer.^name ~ " is not composable, so $.target-name cannot compose it"; + } +} + +my class X::TypeCheck is Exception { + has $.operation; + has $.got; + has $.expected; + method message() { + "Type check failed in $.operation; expected '{$.expected.^name}' but got '{$.got.^name}'"; + + } +} + +my class X::TypeCheck::Binding is X::TypeCheck { + method operation { 'binding' } +} +my class X::TypeCheck::Return is X::TypeCheck { + method operation { 'returning' } + method message() { + "Type check failed for return value; expected '{$.expected.^name}' but got '{$.got.^name}'"; + } +} +my class X::TypeCheck::Assignment is X::TypeCheck { + has $.symbol; + method operation { 'assignment' } + method message { + $.symbol.defined + ?? "Type check failed in assignment to '$.symbol'; expected '{$.expected.^name}' but got '{$.got.^name}'" + !! "Type check failed in assignment; expected '{$.expected.^name}' but got '{$.got.^name}'"; + } +} +my class X::TypeCheck::Argument is X::TypeCheck { + has $.protoguilt; + has @.arguments; + has $.objname; + has $.signature; + method message { + ($.protoguilt ?? "Calling proto of '" !! "Calling '") ~ + $.objname ~ "' " ~ + (+@.arguments == 0 + ?? "requires arguments\n" + !! "will never work with argument types (" ~ join(', ', @.arguments) ~ ")\n") + ~ $.signature + } +} + +my class X::TypeCheck::Splice is X::TypeCheck does X::Comp { + has $.action; + method message { + "Type check failed in {$.action}; expected {$.expected.^name} but got {$.got.^name}"; + } + +} + +my class X::Assignment::RO is Exception { + method message { + "Cannot modify an immutable value"; + } +} + +my class X::Immutable is Exception { + has $.typename; + has $.method; + method message { + "Cannot call '$.method' on an immutable '$.typename'"; + } +} + +my class X::NoDispatcher is Exception { + has $.redispatcher; + method message() { + "$.redispatcher is not in the dynamic scope of a dispatcher"; + } +} + +my class X::Localizer::NoContainer is Exception { + has $.localizer; + method message() { + "Can only use '$.localizer' on a container"; + } +} + +my class X::Mixin::NotComposable is Exception { + has $.target; + has $.rolish; + method message() { + "Cannot mix in non-composable type {$.rolish.^name} into object of type {$.target.^name}"; + } +} + +my class X::Inheritance::Unsupported does X::Comp { + # note that this exception is thrown before the child type object + # has been composed, so it's useless to carry it around. Use the + # name instead. + has $.child-typename; + has $.parent; + method message { + $.parent.^name ~ ' does not support inheritance, so ' + ~ $.child-typename ~ ' cannot inherit from it'; + } +} + +my class X::Inheritance::UnknownParent is Exception { + has $.child; + has $.parent; + has @.suggestions is rw; + + method message { + my $message := "'" ~ $.child ~ "' cannot inherit from '" ~ $.parent ~ "' because it is unknown."; + if +@.suggestions > 1 { + $message := $message ~ "\nDid you mean one of these?\n '" ~ @.suggestions.join("'\n '") ~ "'\n"; + } elsif +@.suggestions == 1 { + $message := $message ~ "\nDid you mean '" ~ @.suggestions[0] ~ "'?\n"; + } + return $message; + } +} + +my class X::Inheritance::SelfInherit is Exception { + has $.name; + + method message { + "'$.name' cannot inherit from itself." + } +} + +my class X::Export::NameClash does X::Comp { + has $.symbol; + method message() { + "A symbol '$.symbol' has already been exported"; + } +} + +my class X::HyperOp::NonDWIM is Exception { + has &.operator; + has $.left-elems; + has $.right-elems; + method message() { + "Lists on both side of non-dwimmy hyperop of &.operator.name() are not of the same length\n" + ~ "left: $.left-elems elements, right: $.right-elems elements"; + } +} + +my class X::Set::Coerce is Exception { + has $.thing; + method message { + "Cannot coerce object of type {$.thing.^name} to Set. To create a one-element set, pass it to the 'set' function"; + } +} + + +my role X::Temporal is Exception { } +my class X::Temporal::InvalidFormat does X::Temporal { + has $.invalid-str; + has $.target = 'Date'; + has $.format; + method message() { + "Invalid $.target string '$.invalid-str'; use $.format instead"; + } +} +my class X::DateTime::TimezoneClash does X::Temporal { + method message() { + 'DateTime.new(Str): :timezone argument not allowed with a timestamp offset'; + } +} +my class X::DateTime::InvalidDeltaUnit does X::Temporal { + has $.unit; + method message() { + "Cannnot use unit $.unit with Date.delta"; + } +} + +my class X::Eval::NoSuchLang is Exception { + has $.lang; + method message() { + "No compiler available for language '$.lang'"; + } +} + +my class X::Import::MissingSymbols is Exception { + has $.from; + has @.missing; + method message() { + "Trying to import from '$.from', but the following symbols are missing: " + ~ @.missing.join(', '); + } +} + +my class X::Numeric::Real is Exception { + has $.target; + has $.reason; + has $.source; + + method message() { + "Can not convert $.source to {$.target.^name}: $.reason"; + } +} + +my class X::Numeric::DivideByZero is Exception { + has $.using; + method message() { + "Divide by zero" ~ ( $.using ?? " using $.using" !! '' ); + } +} + +my class X::PseudoPackage::InDeclaration does X::Comp { + has $.pseudo-package; + has $.action; + method message() { + "Cannot use pseudo package $.pseudo-package in $.action"; + } +} + +my class X::NoSuchSymbol is Exception { + has $.symbol; + method message { "No such symbol '$.symbol'" } +} + +my class X::Item is Exception { + has $.aggregate; + has $.index; + method message { "Cannot index {$.aggregate.^name} with $.index" } +} + +my class X::Multi::Ambiguous is Exception { + has $.dispatcher; + has @.ambiguous; + method message { + join "\n", + "Ambiguous call to '$.dispatcher.name()'; these signatures all match:", + @.ambiguous.map(*.signature.perl) + } +} + +my class X::Multi::NoMatch is Exception { + has $.dispatcher; + method message { + join "\n", + "Cannot call '$.dispatcher.name()'; none of these signatures match:", + $.dispatcher.dispatchees.map(*.signature.perl) + } +} + +my class X::Caller::NotDynamic is Exception { + has $.symbol; + method message() { + "Cannot access '$.symbol' through CALLER, because it is not declared as dynamic"; + } +} + +{ + my %c_ex; + %c_ex{'X::TypeCheck::Binding'} := sub ($got, $expected) is hidden_from_backtrace { + X::TypeCheck::Binding.new(:$got, :$expected).throw; + }; + %c_ex := sub ($symbol, $got, $expected) is hidden_from_backtrace { + X::TypeCheck::Assignment.new(:$symbol, :$got, :$expected).throw; + }; + %c_ex{'X::TypeCheck::Return'} := sub ($got, $expected) is hidden_from_backtrace { + X::TypeCheck::Return.new(:$got, :$expected).throw; + }; + %c_ex := sub () is hidden_from_backtrace { + X::Assignment::RO.new.throw; + }; + %c_ex{'X::ControlFlow::Return'} := sub () is hidden_from_backtrace { + X::ControlFlow::Return.new().throw; + }; + %c_ex{'X::NoDispatcher'} := sub ($redispatcher) is hidden_from_backtrace { + X::NoDispatcher.new(:$redispatcher).throw; + }; + %c_ex{'X::Multi::Ambiguous'} := sub ($dispatcher, @ambiguous) is hidden_from_backtrace { + X::Multi::Ambiguous.new(:$dispatcher, :@ambiguous).throw + }; + %c_ex{'X::Multi::NoMatch'} := sub ($dispatcher) is hidden_from_backtrace { + X::Multi::NoMatch.new(:$dispatcher).throw + }; + my Mu $parrot_c_ex := nqp::getattr(%c_ex, EnumMap, '$!storage'); + nqp::bindcurhllsym('P6EX', $parrot_c_ex); + + 0; +} + + +# vim: ft=perl6 diff --git a/samples/Perl6/Model.pm b/samples/Perl6/Model.pm new file mode 100644 index 00000000..1c2bea9d --- /dev/null +++ b/samples/Perl6/Model.pm @@ -0,0 +1,146 @@ +use v6; + +class Math::Model; + +use Math::RungeKutta; +# TODO: only load when needed +use SVG; +use SVG::Plot; + +has %.derivatives; +has %.variables; +has %.initials; +has @.captures is rw; + +has %!inv = %!derivatives.invert; +# in Math::Model all variables are accessible by name +# in contrast Math::RungeKutta uses vectors, so we need +# to define an (arbitrary) ordering +# @!deriv-names holds the names of the derivatives in a fixed +# order, sod @!deriv-names[$number] turns the number into a name +# %!deriv-keying{$name} translates a name into the corresponding index +has @!deriv-names = %!inv.keys; +has %!deriv-keying = @!deriv-names Z=> 0..Inf; + +# snapshot of all variables in the current model +has %!current-values; + +has %.results; +has @.time; + +has $.numeric-error is rw = 0.0001; + +my sub param-names(&c) { + &c.signature.params».name».substr(1).grep({ $_ ne '_'}); +} + +method !params-for(&c) { + param-names(&c).map( {; $_ => %!current-values{$_} } ).hash; +} + +method topo-sort(*@vars) { + my %seen; + my @order; + sub topo(*@a) { + for @a { + next if %!inv.exists($_) || %seen{$_} || $_ eq 'time'; + die "Undeclared variable '$_' used in model" + unless %.variables.exists($_); + topo(param-names(%.variables{$_})); + @order.push: $_; + %seen{$_}++; + } + } + topo(@vars); +# say @order.perl; + @order; +} + + +method integrate(:$from = 0, :$to = 10, :$min-resolution = ($to - $from) / 20, :$verbose) { + for %.derivatives -> $d { + die "There must be a variable defined for each derivative, missing for '$d.key()'" + unless %.variables.exists($d.key) || %!inv.exists($d.key); + die "There must be an initial value defined for each derivative target, missing for '$d.value()'" + unless %.initials.exists($d.value); + } + + %!current-values = %.initials; + %!current-values