├── run.cmd ├── angen.rb ├── angen ├── trans.rb ├── util.rb ├── ap.rb └── angen.rb ├── README.md ├── test_rake.rb ├── layout.rb ├── shell_android_test.rb ├── COPYING ├── java_android_test.rb └── angen_test.rb /run.cmd: -------------------------------------------------------------------------------- 1 | cd com/M3L/arious 2 | ant release 3 | -------------------------------------------------------------------------------- /angen.rb: -------------------------------------------------------------------------------- 1 | require 'angen/angen.rb' 2 | require 'angen/util.rb' 3 | require 'angen/ap.rb' 4 | require 'angen/trans.rb' 5 | -------------------------------------------------------------------------------- /angen/trans.rb: -------------------------------------------------------------------------------- 1 | require 'ripper' 2 | module Angen 3 | module Translate 4 | def _translate(arr, &b) 5 | if Array === arr[0] 6 | return arr.map{|x| _translate(x, &b)} 7 | end 8 | u = [arr[0]] + arr[1..-1].map{|x| 9 | if Array === x 10 | _translate(x, &b) 11 | else 12 | x 13 | end 14 | } 15 | b.call(u) 16 | end 17 | def translate(a, &b) 18 | r = Ripper.sexp(a) 19 | _translate(r, &b) 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angen 2 | Ange for Another Generator. 3 | P(angen)e? 4 | 5 | Current Test Instructions 6 | ------------- 7 | Requirements: 8 | * Win32 Env(required only by shell\_android\_test.rb) 9 | * ADK (with android-10 installed) 10 | * Ant 11 | * JDK 12 | 13 | ```rake -f test_rake.rb -I . init``` 14 | => generate an Android App skeleton using ADK along with an AVD and a keystore 15 | ```rake -f test_rake.rb -I . edit``` 16 | => generate App UI (res/layout/main.xml) and Main logic (src/Arious.java) 17 | ```rake -f test_rake.rb -I . compile``` 18 | => generate APK 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /angen/util.rb: -------------------------------------------------------------------------------- 1 | module Angen 2 | module Util 3 | extend self 4 | 5 | class MetaObject 6 | def initialize(obj) 7 | @obj = obj 8 | end 9 | 10 | class Methods 11 | def initialize(obj) 12 | @obj = obj 13 | end 14 | def method_missing(sym, *args) 15 | @obj.method(sym) 16 | end 17 | def [](sym) 18 | @obj.method(sym) 19 | end 20 | end 21 | 22 | def M 23 | @m ||= Methods.new(@obj) 24 | end 25 | end 26 | 27 | def _(obj) 28 | MetaObject.new(obj) 29 | end 30 | 31 | def build_array 32 | [].tap{|ret|yield ret.method(:push)} 33 | end 34 | 35 | def build_hash 36 | {}.tap{|ret|yield ret.method(:[]=)} 37 | end 38 | 39 | def compose(f, g) 40 | lambda{|*a| 41 | f.call(g.call(*a)) 42 | } 43 | end 44 | 45 | class ComposeObject 46 | def initialize(obj, f) 47 | @obj = obj 48 | @f = f 49 | end 50 | def method_missing(sym, *args, &b) 51 | @f.call @obj.send(sym, *args, &b) 52 | end 53 | attr_accessor :f 54 | end 55 | 56 | def composeObj(obj, f) 57 | ComposeObject.new(obj, f) 58 | end 59 | 60 | def reduce_with(op, b = nil, &f) 61 | a = [] 62 | op = op.to_proc 63 | b ||= lambda{|u| 64 | if a == [] 65 | a = [u] 66 | else 67 | a = [op.call(a[0], u)] 68 | end 69 | } 70 | f.call(b) 71 | a[0] 72 | end 73 | 74 | def reduce_with_object(obj, op, b = nil) 75 | reduce_with(op, b) do |f| 76 | yield composeObj(obj, f) 77 | end 78 | end 79 | 80 | def def_out(*klasses, &b) 81 | klasses.each{|klass| 82 | if klass < Angen::RootClass::U 83 | klass.send :define_method, :output do 84 | @output ||= value.output 85 | end 86 | elsif klass < Angen::RootClass::T || klass < Angen::RootClass::A 87 | klass.send :define_method, :output do 88 | @output ||= instance_exec(*all, &b) 89 | end 90 | elsif klass < Angen::RootClass::I 91 | klass.send :define_method, :output do 92 | @output ||= instance_exec value, &b 93 | end 94 | elsif klass < Angen::RootClass::L 95 | klass.send :define_method, :output do 96 | @output ||= instance_exec list, &b 97 | end 98 | end 99 | } 100 | end 101 | 102 | 103 | 104 | 105 | end 106 | end -------------------------------------------------------------------------------- /angen/ap.rb: -------------------------------------------------------------------------------- 1 | module Angen 2 | module MonadicEnv 3 | extend Angen 4 | module Identity 5 | def self.bind(a) 6 | yield a 7 | end 8 | def self.unbind(a) 9 | a 10 | end 11 | def self.extract(a) 12 | a 13 | end 14 | end 15 | 16 | Single = I Object 17 | Just = T [Single] 18 | Nothing = T [] 19 | Maybe = Just | Nothing 20 | class Maybe 21 | def self.bind(a, &b) 22 | a.match(Just){|x| 23 | return b.call(x) 24 | }.match(Nothing){ 25 | return Nothing[] 26 | } 27 | end 28 | def self.unbind(a) 29 | Just[a] 30 | end 31 | end 32 | 33 | SingleFunc = I Proc 34 | FuncArrow = T [SingleFunc] 35 | class FuncArrow 36 | def self.bind(a, &b) 37 | a.match(FuncArrow){|f| 38 | FuncArrow[lambda{|x| 39 | f.value[a[x]][x] 40 | }] 41 | } 42 | end 43 | def self.unbind(a) 44 | FuncArrow[lambda{|x| 45 | lambda{|y| 46 | a[y] 47 | } 48 | }] 49 | end 50 | def self.extract(a) 51 | a.match(self){|f| 52 | return f.value 53 | } 54 | end 55 | end 56 | 57 | List = L Single 58 | class List 59 | def self.bind(a, &b) 60 | a.match(List){|*l| 61 | return List[l.flat_map{|x| 62 | b[x] 63 | }] 64 | } 65 | end 66 | def self.unbind(a) 67 | List[a] 68 | end 69 | end 70 | 71 | def ListT(t) 72 | list = L I t 73 | list.class_eval do 74 | def self.bind(a, &b) 75 | a.match(self){|*l| 76 | return self[l.flat_map{|x| 77 | b[x].list 78 | }] 79 | } 80 | end 81 | def self.unbind(a) 82 | self[a] 83 | end 84 | def self.extract(a) 85 | a.match(self){|*l| return l} 86 | end 87 | end 88 | list 89 | end 90 | 91 | def stack 92 | @stack ||= [] 93 | end 94 | 95 | def pushEnv(a) 96 | stack.push(a) 97 | end 98 | 99 | def popEnv 100 | stack.pop 101 | end 102 | 103 | def top 104 | stack.last 105 | end 106 | alias env top 107 | 108 | def bind(a, &b) 109 | top.bind(a, &b) 110 | end 111 | 112 | def unbind(a) 113 | top.unbind(a) 114 | end 115 | 116 | class StatementEnv 117 | def initialize 118 | @things = [] 119 | end 120 | def extract(a) 121 | @things.delete_if{|x| x.hash == a.hash} 122 | a 123 | end 124 | def unbind(a) 125 | @things << a unless @things.index{|x| x.hash == a.hash} 126 | a 127 | end 128 | def result 129 | @things.map{|x| lift(x).rewrite(&method(:rewrite))}.inject(:statement_append_) 130 | end 131 | def lift(x) 132 | x 133 | end 134 | 135 | def rewrite(a) 136 | a 137 | end 138 | end 139 | end 140 | end -------------------------------------------------------------------------------- /test_rake.rb: -------------------------------------------------------------------------------- 1 | require 'shell_android_test' 2 | require 'java_android_test' 3 | require 'layout.rb' 4 | PACKAGE = "com.M3L.arious" 5 | DIR = PACKAGE.tr ".", "/" 6 | FILE = "#{DIR}/src/#{DIR}/Arious.java" 7 | APK = "#{DIR}/bin/Arious-Release.apk" 8 | LAYOUT = "#{DIR}/res/layout/main.xml" 9 | task :init do 10 | Shell::runShell{|run| 11 | createProject PACKAGE 12 | cd DIR 13 | genkey "hello", "world!" 14 | } 15 | end 16 | task :edit do 17 | ti = Time.now 18 | Java.write PACKAGE, FILE do 19 | Control = lambda{|type, id|lambda{let type, Java::Expr[:this].findViewById(Java::Expr.static :R, :id, id).cast(type), [:final]}} 20 | btn = {};button = lambda{|*a|id = Layout.hbutton(*a);btn[a[0]] = Control[:Button, id];id};textEdit = nil 21 | t = Time.now 22 | Layout.write LAYOUT do 23 | topnode(:vertical, :layout_width => "match_parent", :layout_height => "match_parent") do 24 | horizontal{textEdit = Control[:EditText, htext("")] } 25 | ["789+", "456-", "123*", "0.=/"].each{|x| horizontal{x.split("").each{|y| button[y]}}} 26 | horizontal{ button["AC", 2]; button["CE", 2];} 27 | horizontal{["M+", "M-", "MR", "MC"].each{|x| button[x] } } 28 | end 29 | end 30 | puts "Layout used #{Time.now - t}" 31 | import_android "app", "os", "widget", "view", "view.View" 32 | activity("arious"){ 33 | state, op, last, flt, op2, eqpress, mem = let(:Boolean, true), let(:int, 0), let(:float, 0), Java::Expr[:Float], let(:float, 0), let(:Boolean, false), let(:float, 0) 34 | onCreate{|_super, _this, saved| 35 | _super.onCreate saved;_this.setContentView(Java::Expr.static(:R, :layout, :main)) 36 | t = textEdit[]; 37 | addtext = lambda{|x| t.getText.append(x)};settext = lambda{|x| t.getText.clear; t.getText.append(x) };gettext = t.getText.toString 38 | btn.each{|k, v| 39 | v.().setOnClickListener onClickListener{|w| 40 | if(k[/\d|\./]) 41 | Java::Expr.if(state){settext[k]; state.java_value = false}.else{addtext[k]}; eqpress.java_value = false 42 | elsif (r = "+-*/".index(k)) 43 | op.java_value, last.java_value, state.java_value = r, flt.parseFloat(gettext), true; eqpress.java_value = false 44 | elsif k == "=" 45 | Java::Expr.if(eqpress.not){op2.java_value = flt.parseFloat(gettext)} 46 | "+-*/".split("").each_with_index{|x, i| Java::Expr.if(op.eq i){ last.java_value = last.send(x, op2); settext[flt.toString(last)]}} 47 | state.java_value = true 48 | eqpress.java_value = true 49 | elsif k == "AC" 50 | settext[""] 51 | state.java_value = true 52 | eqpress.java_value = false 53 | op.java_value = 0 54 | elsif k == "CE" 55 | settext[""] 56 | state.java_value = true 57 | elsif k == "M+" then mem.java_value += flt.parseFloat(gettext) 58 | elsif k == "M-" then mem.java_value -= flt.parseFloat(gettext) 59 | elsif k == "MR" then settext[flt.toString(mem)] 60 | elsif k == "MC" then mem.java_value = 0 61 | end 62 | } 63 | } 64 | } 65 | } 66 | end 67 | puts "Java used #{Time.now - ti}" 68 | end 69 | task :compile => APK 70 | file APK => FILE do 71 | Shell::runShell{|run| 72 | cd DIR 73 | ant "release" 74 | } 75 | end 76 | 77 | task :reinstall do 78 | Shell.runShell{|run| 79 | adb "uninstall", PACKAGE 80 | adb "install", APK, ENV["emulator"] 81 | } 82 | end 83 | -------------------------------------------------------------------------------- /layout.rb: -------------------------------------------------------------------------------- 1 | require 'angen' 2 | module Layout 3 | extend Angen 4 | extend Angen::Util 5 | extend Angen::MonadicEnv 6 | 7 | Extract = lambda{|x| env.extract(x)} 8 | Unbind = lambda{|x| env.unbind(x)} 9 | Lift = lambda{|x| env.lift(x)} 10 | pushEnv Angen::MonadicEnv::Identity 11 | class Rewriter < Angen::MonadicEnv::StatementEnv 12 | def rewrite(a) 13 | a 14 | end 15 | def lift(x) 16 | Expr[x] 17 | end 18 | end 19 | indent_size = 0 20 | Indent = lambda{|&b| 21 | begin 22 | r = b.call 23 | return r.split("\n").map{|x| " " + x }.join("\n") 24 | ensure 25 | 26 | end 27 | } 28 | 29 | #--------------LANGUAGE------------------------------------------------------------- 30 | type.Str String 31 | type.Tag Symbol 32 | type.AttrName Symbol 33 | type.Attr Hash 34 | list.Childnode rec.XMLNode 35 | type.AttrValue String 36 | XMLAttr = AttrName | AttrValue 37 | XMLNode = T [Tag, Attr, Childnode], [:tagname, :attrs, :node] 38 | class XMLNode 39 | def unbind(node) 40 | self.node.list << node unless self.node.list.index{|x| x.hash == node.hash} 41 | node 42 | end 43 | def extract(node) 44 | self.node.list.delete_if{|x| x.hash == node.hash} 45 | node 46 | end 47 | end 48 | 49 | def_out Str do |s| s.inspect end 50 | def_out Tag do |s| s.to_s end 51 | def_out Attr do |s| 52 | s.empty? ? "" : " " + 53 | s.map{|k, v| 54 | "#{XMLAttr[AttrName[k.to_sym]].output} = #{XMLAttr[AttrValue[v.to_s]].output}" 55 | }.join(" ") 56 | end 57 | def_out XMLAttr do |s| value.output end 58 | def_out AttrName do |s| s.to_s end 59 | def_out AttrValue do |s| s.inspect end 60 | def_out XMLNode do |tag, attr, children| 61 | if children.list.empty? 62 | "<#{tag.output}#{attr.output}/>" 63 | else 64 | "<#{tag.output}#{attr.output}>\n#{Indent.call{children.output}}\n" 65 | end 66 | end 67 | def_out Childnode do |list| 68 | list.map(&:output).join("\n") 69 | end 70 | 71 | 72 | 73 | def self.define_verb(*a) 74 | a.each{|tagname| 75 | (class << self; self; end).send :define_method, tagname do |opt = {}, &b| 76 | pushEnv XMLNode[tagname, opt, []] 77 | b.call if b 78 | r = popEnv 79 | Unbind[r] 80 | r 81 | end 82 | } 83 | end 84 | 85 | def self.define_android_verb(*a) 86 | a.each{|tagname| 87 | (class << self; self; end).send :define_method, tagname do |opt = {}, &b| 88 | pushEnv XMLNode[tagname, opt.map{|k, v| ["android:#{k}".to_sym, v]}.to_h, []] 89 | b.call if b 90 | r = popEnv 91 | Unbind[r] 92 | r 93 | end 94 | } 95 | end 96 | 97 | def self.topnode(tagname, opt = {}, &b) 98 | u = send(tagname, opt, &b) 99 | u[1].value = {:"xmlns:android"=>"http://schemas.android.com/apk/res/android", 100 | :"xmlns:tools"=>"http://schemas.android.com/tools", 101 | :"android:orientation"=>"vertical", 102 | :"android:layout_width"=>"match_parent", 103 | :"android:layout_height"=>"match_parent", 104 | :"android:background"=>"#FFFFFF", 105 | :"tools:context"=>".MainActivity"}.merge(u[1].value) 106 | u 107 | end 108 | define_android_verb :LinearLayout 109 | define_android_verb :Button 110 | define_android_verb :EditText 111 | def self.horizontal(opt = {}) 112 | LinearLayout({layout_width: "match_parent", layout_height: "wrap_content", orientation: "horizontal"}.merge(opt))do 113 | yield 114 | end 115 | end 116 | 117 | def self.vertical(opt = {}) 118 | LinearLayout({layout_width: "wrap_content", layout_height: "match_parent", orientation: "vertical"}.merge(opt))do 119 | yield 120 | end 121 | end 122 | 123 | @id = 0 124 | def self.define_hcontrol(name, name2) 125 | (class << self; self; end).send :define_method, name do |text = "", len = 1, width = "match_parent", height = "wrap_content", name = "__btn#{@id+=1}"| 126 | send name2, layout_width: width.to_s, layout_height: height.to_s, text: text.to_s, layout_weight: len.to_s, id: "@+id/#{name}" 127 | name 128 | end 129 | end 130 | 131 | define_hcontrol(:hbutton, :Button) 132 | define_hcontrol(:htext, :EditText) 133 | 134 | def self.write(a, &b) 135 | IO.write a, run{ 136 | class_exec &b 137 | } 138 | end 139 | 140 | def self.run(&b) 141 | class_exec(&b).output 142 | end 143 | end 144 | 145 | -------------------------------------------------------------------------------- /shell_android_test.rb: -------------------------------------------------------------------------------- 1 | require 'angen' 2 | module Shell 3 | extend Angen 4 | extend Angen::Util 5 | extend Angen::MonadicEnv 6 | 7 | Extract = lambda{|x| env.extract(x)} 8 | Unbind = lambda{|x| env.unbind(x)} 9 | Lift = lambda{|x| env.lift(x)} 10 | class RewriteShell < Angen::MonadicEnv::StatementEnv 11 | def rewrite(a) 12 | a.match(Dict){|a| 13 | return rewrite(Opt[a.value.to_a]) 14 | }.match(CreateProject){|a| 15 | r = nil 16 | a.match(Opt){|list| 17 | r = rewrite(Args[list.flat_map{|x| [x._0, x._1]}]) 18 | r.match(Args){ |list| 19 | return Command["call", ["android", "create", "project"] + list] 20 | } 21 | } 22 | 23 | }.match(CreateAVD){|a| 24 | r = nil 25 | a.match(Opt){|list| 26 | r = rewrite(Args[list.flat_map{|x| [x._0, x._1]}]) 27 | r.match(Args){ |list| 28 | return Command["call", ["android", "create", "avd"] + list] 29 | } 30 | } 31 | }.match(ListTarget){ 32 | return Command["call", ["android", "list", "target"]] 33 | } 34 | a 35 | end 36 | end 37 | 38 | class Run < RewriteShell 39 | def lift(x) 40 | ShellRun[[x]] 41 | end 42 | end 43 | 44 | class Show < RewriteShell 45 | def lift(x) 46 | ShellShow[[x]] 47 | end 48 | end 49 | 50 | type.Str String 51 | type.Dict Hash 52 | list.Opt A [Str, Str] 53 | ctor.CreateProject Opt 54 | ctor.ListTarget 55 | Android = CreateProject | ListTarget | rec.Command | ctor.CreateAVD(Opt) 56 | Shell = ctor.Command(Str, list.Args(Str)) | rec.Android 57 | 58 | list.ShellRun Shell 59 | list.ShellShow Shell 60 | 61 | class Shell 62 | def >>(rhs) 63 | Lift[self] >> rhs 64 | end 65 | alias statement_append_ >> 66 | def output 67 | value.output 68 | end 69 | end 70 | 71 | class Command 72 | def output 73 | match(Command) do |str, args| 74 | return "#{str.output} #{args.output}" 75 | end 76 | end 77 | end 78 | 79 | class Android 80 | def output 81 | self.value.output 82 | end 83 | end 84 | 85 | class ShellRun 86 | def >>(rhs) 87 | rhs.match(ShellRun){|a| 88 | return ShellRun[list + a] 89 | }.match(Shell){|a| 90 | return ShellRun[list + [rhs]] 91 | } 92 | end 93 | alias statement_append_ >> 94 | end 95 | 96 | class ShellShow 97 | def >>(rhs) 98 | rhs.match(ShellShow){|a| 99 | return ShellShow[list + a] 100 | }.match(Shell){|a| 101 | return ShellShow[list + [rhs]] 102 | } 103 | end 104 | alias statement_append_ >> 105 | end 106 | 107 | class Args 108 | def output 109 | match(Args) do |*args| 110 | return args.map{|x| x.map(&:output)}.join(' ') 111 | end 112 | end 113 | end 114 | 115 | 116 | 117 | class Str 118 | def output 119 | if (self.value[' '] || self.value['"']) && !(self.value =~ /^"[^"]*"$/) 120 | self.value.inspect 121 | else 122 | self.value 123 | end 124 | end 125 | end 126 | 127 | def self.sh(a) 128 | Unbind[a] 129 | end 130 | 131 | def self.command(a, *b) 132 | Command[a, Args[b]] 133 | end 134 | 135 | def self.tree(&b) 136 | x = const_get((b.parameters[0] || ["", "Run"]).last.capitalize) 137 | pushEnv x.new 138 | class_eval &b 139 | popEnv 140 | end 141 | 142 | def self.runShell(&b) 143 | r = tree(&b).result 144 | open "run.cmd", "w" do |f| 145 | r.list.each{|x| 146 | f.write x.output 147 | f.write "\n" 148 | } 149 | end 150 | r.match(ShellRun){|a| 151 | system "run.cmd" 152 | }.match(ShellShow){|a| 153 | system "type run.cmd" 154 | } 155 | end 156 | 157 | 158 | def self.rubyeval(a) 159 | sh command "ruby", "-e", a 160 | end 161 | 162 | def self.genkey(als, pass, file = "main.keystore", alg = "RSA", validity = "365") 163 | Unbind[Command["call", ["keytool", "-genkey", "-alias", als, "-keystore", file, "-storepass", pass, "-keypass", pass, "-keyalg", alg, "-validity", validity]]] 164 | appendLine "local.properties", "key.store=#{file}" 165 | appendLine "local.properties", "key.alias=#{als}" 166 | end 167 | 168 | def self.genavd(name , target, size = "10M") 169 | Unbind[CreateAVD[[["-t", target], ["-n", name], ["-c", size.to_s]]]] 170 | end 171 | def self.createProject(package, activity = package.split(".").last.capitalize, target = "android-10", path = package.tr(".", "/")) 172 | Unbind[CreateProject[[["-k", package], ["-t", target], ["-p", path], ["-a", activity]]]] 173 | genavd package, target 174 | end 175 | 176 | def self.listTarget 177 | Unbind[ListTarget[]] 178 | end 179 | 180 | def self.define_shell(a) 181 | (class << self; self; end).send :define_method, a do |*args| 182 | sh command a.to_s, *args 183 | end 184 | end 185 | 186 | def self.appendLine(a, b) 187 | Unbind[Command["echo", [b + ">>" + a]]] 188 | end 189 | 190 | define_shell :cd 191 | define_shell :ant 192 | define_shell :adb 193 | end 194 | 195 | 196 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2016 Seiran Hana(pochy2008@qq.com) 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /java_android_test.rb: -------------------------------------------------------------------------------- 1 | require 'angen' 2 | module Java 3 | extend Angen 4 | extend Angen::Util 5 | extend Angen::MonadicEnv 6 | 7 | Extract = lambda{|x| env.extract(x)} 8 | Unbind = lambda{|x| env.unbind(x)} 9 | Lift = lambda{|x| env.lift(x)} 10 | pushEnv Angen::MonadicEnv::Identity 11 | class Rewriter < Angen::MonadicEnv::StatementEnv 12 | def rewrite(a) 13 | a 14 | end 15 | def lift(x) 16 | Expr[x] 17 | end 18 | end 19 | indent_size = 0 20 | Indent = lambda{|&b| 21 | begin 22 | r = b.call 23 | return r.split("\n").map{|x| " " + x }.join("\n") 24 | ensure 25 | 26 | end 27 | } 28 | 29 | def self.def_out(*klasses, &b) 30 | klasses.each{|klass| 31 | if klass < Angen::RootClass::U 32 | klass.send :define_method, :output do 33 | value.output 34 | end 35 | elsif klass < Angen::RootClass::T || klass < Angen::RootClass::A 36 | klass.send :define_method, :output do 37 | match(klass) do |*a| return instance_exec(*a, &b) end 38 | end 39 | elsif klass < Angen::RootClass::I 40 | klass.send :define_method, :output do 41 | instance_exec &b 42 | end 43 | elsif klass < Angen::RootClass::L 44 | klass.send :define_method, :output do 45 | instance_exec list, &b 46 | end 47 | end 48 | } 49 | end 50 | 51 | #--------------LANGUAGE------------------------------------------------------------- 52 | 53 | type.Str String 54 | type.Int Integer 55 | type.Flt Float 56 | type.Ident Symbol 57 | type.True true 58 | type.False false 59 | type.BinOp(/[\+\-\*\/%^&|\.]|\|\||\&\&|>|<|>=|<=|==|!=|>>|<<|=/) 60 | type.PrefixUnOp(/[\+\-]|\+\+|--|!|~/) 61 | type.SuffixUnOp(/\+\+|--/) 62 | ctore.Typename(Ident) 63 | ctore.Var(Ident) 64 | 65 | list.Modifiers Ident 66 | Annotation = ctore.Marker(Ident) 67 | list.Annotations Annotation 68 | ctor.Decl Ident, rec.Expr, optional.InitValue(rec.Expr), rec.Modifiers 69 | list.ArgDecls Decl 70 | list.Implements Ident 71 | Expr = Str | Int | Flt | Ident | Decl | True | False | 72 | ctor.BinaryExpr(BinOp, rec.Expr, rec.Expr) | 73 | ctor.PrefixUnary(PrefixUnOp, rec.Expr) | 74 | ctor.SuffixUnary(rec.Expr, SuffixUnOp) | 75 | ctore.Cast(Ident, rec.Expr) | 76 | ctore.Index(rec.Expr, rec.Expr) | 77 | ctore.Call(rec.Expr, list.ArgList(rec.Expr)) | 78 | ctore.Ternary(rec.Expr, rec.Expr, rec.Expr) | 79 | list.Statements(rec.Expr) | 80 | ctore.FuncDecl(Annotations, Modifiers, Ident, Ident, ArgDecls, rec.Block)| 81 | ctore.ClassDecl(Annotations, Modifiers, Ident, Ident, Implements,rec.Block) | 82 | ctore.Package(Str) | 83 | ctore.Import(Str) | 84 | ctore.Block(Statements) | 85 | ctore.Paren(rec.Expr) | 86 | ctore.Java7Lam(Ident, FuncDecl) | 87 | ctore.If(rec.Expr, Block, optional.Block_(Block)) | 88 | ctore.For(rec.Expr, rec.Expr, rec.Expr, Block) | 89 | ctore.While(rec.Expr, Block) 90 | 91 | 92 | def_out Expr do value.output end 93 | def_out Str, Int, Flt do value.inspect end 94 | def_out BinOp, Ident, SuffixUnOp, PrefixUnOp, True, False do value.to_s end 95 | def_out BinaryExpr do |a, b, c| "#{b.output}#{a.output}#{c.output}" end 96 | def_out PrefixUnary do |a, b| "#{a.output}#{b.output}" end 97 | def_out Cast do |a, b| "(#{a.output})#{b.output}" end 98 | def_out SuffixUnary do |a, b| "#{a.output}#{b.output}" end 99 | def_out Paren do |expr| "(#{expr.output})" end 100 | def_out Index do |a, b| "#{a.output}[#{b.output}]" end 101 | def_out Call do |a, b| "#{a.output}(#{b.output})" end 102 | def_out Ternary do |a, b, c| "(#{a.output}) ? (#{b.output}) : (#{c.output})" end 103 | def_out ArgList do |list| list.map(&:output).join(",") end 104 | def_out Statements do |list| list.map(&:output).join(";\n") + ";\n" end 105 | def_out Java7Lam do |name, func| 106 | "(new #{name.output}(){#{Indent.call{func.output}}\n})" 107 | end 108 | class InitValue 109 | def output 110 | unless Angen::RootClass::N === value 111 | " = #{value.output}" 112 | else 113 | "" 114 | end 115 | end 116 | end 117 | def_out Decl do |type, name, init, modifiers| "#{modifiers.output}#{type.output} #{name.output}#{init.output}" end 118 | def_out FuncDecl do |an, mo, ret, name, args, body| 119 | "#{an.output}\n#{mo.output}#{ret.output} #{name.output}(#{args.output})#{body.output}" 120 | end 121 | def_out ClassDecl do |an, mo, name, ext, impl, body| 122 | "#{an.output}\n#{mo.output}class #{name.output} extends #{ext.output}#{impl.output}#{body.output}" 123 | end 124 | def_out Annotations do |list| list.map(&:output).join("\n") end 125 | def_out Modifiers do |list| list.map(&:output).join(" ") + (list.empty? ? "" : " ") end 126 | def_out ArgDecls do |list| list.map(&:output).join(",") end 127 | def_out Marker do |val| "@#{val.value}" end 128 | def_out Implements do |list| list.empty? ? "" : " implements " + list.map(&:output).join(",") end 129 | def_out Package do |val| "package #{val.value}" end 130 | def_out Import do |val| "import #{val.value}" end 131 | def_out Block do |val| "{\n#{Indent.call{val.output}}\n}" end 132 | def_out If do |cond, thenp, elsep| "if(#{cond.output})#{Indent.call{thenp.output}}#{Angen::RootClass::N === self[2].value ? "" : "else#{Indent.call{self[2].value.output}}"}" end 133 | #-----------------------------------RUNNER------------------------------------------------ 134 | 135 | class Expr 136 | 137 | def self.define_binop(*as) 138 | as.each{|a| 139 | define_method a do |rhs| 140 | effect rhs do |s, rhs| 141 | Expr[BinaryExpr[a, s, rhs]] 142 | end 143 | end 144 | } 145 | end 146 | 147 | def self.define_prefixop(opt = {}) 148 | opt.each{|k, v| 149 | define_method v do 150 | effect do |s| 151 | Expr[PrefixUnary[k, s]] 152 | end 153 | end 154 | } 155 | end 156 | 157 | def self.define_suffixop(opt = {}) 158 | opt.each{|k, v| 159 | define_method v do 160 | effect do |s| 161 | Expr[SuffixUnary[s, k]] 162 | end 163 | end 164 | } 165 | end 166 | 167 | def cast(type) 168 | effect do |s| 169 | Expr[Cast.unchecked(type, s)] 170 | end 171 | end 172 | def paren 173 | effect{|s| Expr[Paren.unchecked(s)] } 174 | end 175 | 176 | def effect(*a) 177 | Unbind[yield(*[self, *a].map{|x| Extract[x]})] 178 | end 179 | 180 | def statement_append_(rhs) 181 | if Statements === value 182 | u = value.clone 183 | u.list << rhs 184 | Expr[Statements[u]] 185 | else 186 | Expr[Statements[[self]]].statement_append_(rhs) 187 | end 188 | end 189 | 190 | def to_statement_ 191 | self.value.match(Statements){|s| return Expr[Statements[s]] } 192 | return Expr[Statements[[self]]] 193 | end 194 | 195 | def assign(rhs) 196 | send "=", rhs 197 | end 198 | 199 | def eq(rhs) 200 | send "==", rhs 201 | end 202 | 203 | define_binop '+', '-', '*', '/', '==', '>=' , '=', '<=', '!=', '<', '>', '%', '^', '&', '&&', '|', '||', '>>', '<<' 204 | define_prefixop '++' => 'inc_p', '--' => 'dec_p', '!' => "not" 205 | define_suffixop '++' => 'inc_s', '--' => 'dec_s' 206 | @varid = 0 207 | def self.var(type, value = Angen::RootClass::N[], m = [], id = :"__var$#{@varid+=1}") 208 | x = Expr[Ident[id]] 209 | x.effect(type, value){|s, t, v| Expr[Decl[t,s,InitValue[v],m]]} 210 | x 211 | end 212 | 213 | 214 | def field(a) 215 | effect a do |s, a| Expr[BinaryExpr[".", s, a]] end 216 | end 217 | 218 | def invoke(a, *args) 219 | effect a, *args do |s, a, *args| Expr[Call.unchecked(Expr[BinaryExpr[".", s, a]], args) ] end 220 | end 221 | 222 | def index(a) 223 | effect a do |s, a| Expr[Index[s, a]] end 224 | end 225 | 226 | attr_accessor :point, :index 227 | 228 | def method_missing(sym, *args) 229 | r = sym.to_s 230 | if r["="] 231 | self.field(sym).send("=", args[0]) 232 | else 233 | invoke(sym, *args) 234 | end 235 | end 236 | 237 | def self.static(*a) 238 | Expr[ a.join(".").to_sym ] 239 | end 240 | 241 | Fn = Struct.new(:annotations, :modifiers, :ret, :name, :args) 242 | class Fn 243 | def mark(*a) 244 | a.each{|a| 245 | (self.annotations ||= []).push Marker.unchecked(a.to_sym) 246 | } 247 | self 248 | end 249 | def as(*a) 250 | a.each{|a| 251 | (self.modifiers ||= []).push a.to_sym 252 | } 253 | self 254 | end 255 | def returns(ret) 256 | self.ret = ret.to_sym 257 | self 258 | end 259 | def arg(a, b, c = Angen::RootClass::N[], d = []) 260 | (self.args ||= []) << Decl[a, b, c, d] 261 | self 262 | end 263 | def named(a) 264 | self.name = a 265 | self 266 | end 267 | def create(&a) 268 | Expr.fn(self, &a) 269 | end 270 | end 271 | 272 | Klass = Struct.new(:annotations, :modifiers, :name, :ext, :imp) 273 | class Klass 274 | def mark(*a) 275 | a.each{|a| 276 | (self.annotations ||= []).push Marker.unchecked(a.to_sym) 277 | } 278 | self 279 | end 280 | def as(*a) 281 | a.each{|a| 282 | (self.modifiers ||= []).push a.to_sym 283 | } 284 | self 285 | end 286 | def extends(e) 287 | self.ext = e 288 | self 289 | end 290 | def implements(*a) 291 | (self.imp ||= []).concat a 292 | self 293 | end 294 | def named(a) 295 | self.name = a 296 | self 297 | end 298 | def create(&a) 299 | Expr.klass(self, &a) 300 | end 301 | end 302 | 303 | def self.if(expr, &block) 304 | Unbind[Expr[If.unchecked(Extract[expr], Extract[self.blk(&block)].value, Angen::RootClass::N[] ) ] ] 305 | end 306 | 307 | def self.for(expr1, expr2, expr3, &block) 308 | Unbind[Expr[For.unchecked(Extract[expr1], Extract[expr2], Extract[expr3], Extract[self.blk(&block)].value) ] ] 309 | end 310 | 311 | def java_value=(rhs) 312 | assign rhs 313 | end 314 | def java_value 315 | self 316 | end 317 | def else(&block) 318 | Extract[self] 319 | self.value.match(If) do |expr, thenpart, elsepart| 320 | return Unbind[Expr[If.unchecked(Extract[expr], Extract[thenpart], Block_[Extract[Expr.blk(&block)].value ]) ] ] 321 | end 322 | raise 'not an If statement' 323 | end 324 | 325 | def self.blk(&bl) 326 | r = Java.tree(&bl).result 327 | Expr[Block.unchecked(r.to_statement_.value)] 328 | end 329 | 330 | def self.fn(fn, &bl) 331 | Unbind[Expr[FuncDecl.unchecked(fn.annotations || [], fn.modifiers || [], fn.ret || :void, fn.name, fn.args || [], blk(&bl).value)]] 332 | end 333 | 334 | def self.klass(kl, &bl) 335 | Unbind[Expr[ClassDecl.unchecked(kl.annotations || [], kl.modifiers || [], kl.name, kl.ext || :Object, kl.imp ||[], blk(&bl).value)]] 336 | end 337 | 338 | def self.handler(name, f) 339 | Unbind[Java7Lam.unchecked(Extract[name].to_sym, Extract[f].value)] 340 | end 341 | end 342 | 343 | def self.name_alias(sym) 344 | return sym.to_s[1..-1].to_sym if sym.to_s[0] == "_" 345 | sym 346 | end 347 | def self.tree(&b) 348 | pushEnv Rewriter.new 349 | class_exec *b.parameters.map{|x| Expr[name_alias(x.last)]}, &b 350 | popEnv 351 | end 352 | 353 | def self.run(&b) 354 | r = tree(&b).result 355 | r.output 356 | end 357 | 358 | def self.package(a) 359 | Unbind[Package.unchecked a.to_s] 360 | end 361 | 362 | def self.import(a) 363 | Unbind[Import.unchecked a.to_s] 364 | end 365 | 366 | N = Angen::RootClass::N[] 367 | 368 | def self.activity(name, &b) 369 | Java::Expr::Klass.new.named(name.capitalize.to_sym).as(:public).extends(:Activity).create(&b) 370 | end 371 | 372 | def self.onCreate(types = [:"android.os.Bundle"], &b) 373 | fn = Java::Expr::Fn.new.named(:onCreate).as(:public).returns(:void).mark(:Override) 374 | b.parameters.select{|x| x.last.to_s !~ /^_/}.each_with_index{|x, i| 375 | fn.arg types[i], x.last 376 | } 377 | fn.create(&b) 378 | end 379 | 380 | class NS 381 | def method_missing(*a) 382 | Expr.static(*a) 383 | end 384 | end 385 | def self.ns(*a) 386 | if a == [] 387 | NS.new 388 | else 389 | Expr.static *a 390 | end 391 | end 392 | 393 | def self.import_android(*a) 394 | a.each{|a| 395 | import "android.#{a}.*" 396 | } 397 | end 398 | 399 | def self.write(pkg, a, &b) 400 | IO.write a, run{ 401 | package pkg 402 | class_exec &b 403 | } 404 | end 405 | 406 | def self.onClickListener(&b) 407 | fn = Java::Expr::Fn.new.named(:onClick).as(:public).returns(:void) 408 | types = [:View] 409 | b.parameters.select{|x| x.last.to_s !~ /^_/}.each_with_index{|x, i| 410 | fn.arg types[i], x.last 411 | } 412 | Expr.handler(:"OnClickListener", fn.create(&b)) 413 | end 414 | 415 | def self.let(*a, &b) 416 | Java::Expr.var(*a, &b) 417 | end 418 | 419 | 420 | end 421 | 422 | 423 | -------------------------------------------------------------------------------- /angen_test.rb: -------------------------------------------------------------------------------- 1 | require 'angen' 2 | module JS 3 | extend Angen 4 | extend Angen::Util 5 | extend Angen::MonadicEnv 6 | module WithThis 7 | def self.included(a) 8 | a.extend self 9 | end 10 | def classname a 11 | @name = a 12 | end 13 | def this 14 | Expr[:this] 15 | end 16 | def ret(a) 17 | Expr.ret(a) 18 | end 19 | end 20 | #---------TEST--------------------------------------------------------------- 21 | Unary = I(:+) | I(:-) | I(:"!") 22 | Binary = I(:+) | I(:-) | I(:*) | I(:/) | I(:"=") | I(:==) | I(:".") | I(:">") | I(:"<") | I(:%) | I(:===) 23 | Expr = type.Num(Integer) \ 24 | | type.Str(String) \ 25 | | type.Var(Symbol) \ 26 | | list.Arr(rec.Expr) \ 27 | | type.Tr(TrueClass) \ 28 | | type.Fa(FalseClass) \ 29 | | type.Lam(Proc) \ 30 | | type.OpenClass(WithThis) \ 31 | | ctore.Arg(Num) \ 32 | | ctor.Do(list.Statements(rec.Expr)) \ 33 | | ctore.Fn(list.ArgList(rec.Expr), rec.Do) \ 34 | | ctore.Block(ArgList, rec.Do) \ 35 | | ctor.FCall(rec.Expr, ArgList) \ 36 | | ctor.UExpr(Unary, rec.Expr) \ 37 | | ctor.BExpr(Binary, rec.Expr, rec.Expr) \ 38 | | ctore.Ret(rec.Expr) \ 39 | | ctore.PExpr(rec.Expr) \ 40 | | ctor.VarA(Var, rec.Expr) \ 41 | | ctor.If(rec.Expr,Block, optional.Block_(Block)) \ 42 | | ctor.While(rec.Expr,Block) \ 43 | | ctor.For(rec.Expr, rec.Expr, rec.Expr, Block) \ 44 | | ctor.DoWhile(Block, rec.Expr) \ 45 | | ctore.Break() \ 46 | | ctore.Continue() \ 47 | | ctor.Index(rec.Expr, rec.Expr) \ 48 | 49 | 50 | # ------------- Impl ------------------------------------------------- 51 | pushEnv Angen::MonadicEnv::Identity 52 | Extract = lambda{|x| env.extract(x)} 53 | Unbind = lambda{|x| env.unbind(x)} 54 | 55 | module AutoEnv 56 | def method_added(sym) 57 | return if @__defining 58 | @__defining = true 59 | x = instance_method(sym) 60 | define_method sym do |*a, &b| 61 | Unbind[x.bind(Extract[self]).call(*(a + Array(b)).map(&Extract))] 62 | end 63 | @__defining = false 64 | end 65 | end 66 | 67 | class Expr 68 | alias to_str inspect 69 | extend AutoEnv 70 | def +(rhs) 71 | Expr[BExpr[:+, self, rhs]] 72 | end 73 | def -(rhs) 74 | Expr[BExpr[:-, self, rhs]] 75 | end 76 | def *(rhs) 77 | Expr[BExpr[:*, self, rhs]] 78 | end 79 | def /(rhs) 80 | Expr[BExpr[:/, self, rhs]] 81 | end 82 | def %(rhs) 83 | Expr[BExpr[:%, self, rhs]] 84 | end 85 | def >(rhs) 86 | Expr[BExpr[:>, self, rhs]] 87 | end 88 | def <(rhs) 89 | Expr[BExpr[:<, self, rhs]] 90 | end 91 | def eq(rhs) 92 | Expr[BExpr[:===, self, rhs]] 93 | end 94 | def assign(rhs) 95 | Expr[BExpr[:"=", self, rhs]] 96 | end 97 | def paren 98 | Expr[PExpr.unchecked(self)] 99 | end 100 | def self.ret(rhs) 101 | Expr[Do[Statements[[Ret.unchecked(rhs)]]]] 102 | end 103 | def statement_append(rhs) 104 | r = to_statement 105 | u = Expr[rhs].to_statement 106 | r._0.list += u._0.list 107 | Expr[r] 108 | end 109 | 110 | 111 | def self.fn(a) 112 | lambda{|*args| 113 | Unbind[Expr[FCall[Extract[a], args.map{|x| Extract[x]}]]] 114 | } 115 | end 116 | def self.def(fname) 117 | x = Proc.new 118 | args = x.parameters.map{|a| a.last} 119 | Expr[Do[Statements[[FDecl[fname, args, yield(*args.map{|x| Expr[x]}).to_statement]]]]] 120 | end 121 | def self.method_missing(sym, *args, &b) 122 | fn(sym).call(*(args + Array(b))) 123 | end 124 | def self.js(sym, *args, &b) 125 | fn(sym).call(*(args + Array(b))) 126 | end 127 | 128 | def not 129 | Expr[UExpr[:'!', Extract[self.paren]]] 130 | end 131 | 132 | def to_statement 133 | if Do === self.value 134 | r = self.value.clone 135 | else 136 | r = Do[Statements[[self]]] 137 | end 138 | r 139 | end 140 | 141 | def [](rhs) 142 | Expr[BExpr[:'.', self, rhs]] 143 | end 144 | 145 | def method_missing(sym, *args, &b) 146 | Expr.js(:"#{JS.output self, 0}.#{sym}", *args.map{|x| x}) 147 | end 148 | def self.ffi(name, typeargs) 149 | t = Angen.T typeargs 150 | lambda{|*args, &b| 151 | raise TypeError, "in ffi #{name} #{t} #{args}" if !(t.===(*args)) 152 | Var.from(Expr.js(name, *args)) 153 | } 154 | end 155 | 156 | 157 | def index(arg, &block) 158 | Unbind[Expr[Index[Extract[self], Extract[arg]]]] 159 | end 160 | 161 | 162 | def call(*args, &block) 163 | Expr.js(self.paren, *(args + Array(block)).map{|x| x}) 164 | end 165 | 166 | def self.if(expr, &block) 167 | Unbind[Expr[If[Extract[expr], Extract[self.blk(&block)].value, Angen::RootClass::N[] ] ] ] 168 | end 169 | 170 | def self.for(expr1, expr2, expr3, &block) 171 | Unbind[Expr[For[Extract[expr1], Extract[expr2], Extract[expr3], Extract[self.blk(&block)].value] ] ] 172 | end 173 | 174 | def else(block) 175 | self.value.match(If) do |expr, thenpart, elsepart| 176 | return Unbind[Expr[If[Extract[expr], Extract[thenpart], Block_[Extract[Expr.blk(&block)].value ]] ] ] 177 | end 178 | raise 'not an If statement' 179 | end 180 | 181 | def self.fun(&block) 182 | params = block.parameters.map{|x| x.last}.map{|x| 183 | x[0] == '_' ? x[1..-1] : x 184 | } 185 | env = MyIdentity.new 186 | JS.pushEnv env 187 | r = yield(*params.map{|x| Expr[Var[x]]}) 188 | re = Expr[Fn.unchecked(params, Expr[env.result].to_statement)] 189 | JS.popEnv 190 | re 191 | end 192 | 193 | def self.blk(&block) 194 | params = block.parameters.map{|x| x.last}.map{|x| 195 | x[0] == '_' ? x[1..-1] : x 196 | } 197 | env = MyIdentity.new 198 | JS.pushEnv env 199 | r = yield(*params.map{|x| Expr[Var[x]]}) 200 | re = Expr[Block.unchecked(params, Expr[env.result].to_statement)] 201 | JS.popEnv 202 | re 203 | end 204 | 205 | def []=(a, b) 206 | self[a].assign b 207 | end 208 | end 209 | class Var 210 | @_id = 10000 211 | def self.from(rhs, name = nil) 212 | name ||= begin 213 | x = Proc.new 214 | @_id += 1 215 | :"#{x.parameters[0].last}$#{@_id}" 216 | rescue 217 | @_id += 1 218 | :"_var$#{@_id}" 219 | end 220 | Unbind[Expr[VarA[name, Extract[rhs]]]] 221 | Expr[name] 222 | end 223 | def self.let(rhs, name = nil, &b) 224 | self.from(rhs, name, &b) 225 | end 226 | def method_missing(sym, *args, &b) 227 | if sym.to_s["="] 228 | r = sym.to_s.sub(/=/, "") 229 | Unbind[Expr[Extract[:"#{@path}.#{r}"]].assign(Extract[args[0]])] 230 | else 231 | if args.empty? 232 | if !block_given? 233 | Var[:"#{self.value}.#{sym}"] 234 | else 235 | Expr.js(:"#{self.value}.#{sym}", *(args+Array(b))) 236 | end 237 | else 238 | Expr.js(:"#{self.value}.#{sym}", *(args + Array(b))) 239 | end 240 | end 241 | end 242 | end 243 | 244 | Console = Module.new do 245 | def self.method_missing(sym, *args) 246 | Expr.js :"console.#{sym}", *args 247 | end 248 | def self.log(*args) 249 | Expr.js :"console.log", *args 250 | end 251 | end 252 | 253 | 254 | def self.eliminate(u) 255 | while Ret === u 256 | u = u[0] 257 | end 258 | u 259 | end 260 | # 1 261 | 262 | def self.output(expr, indent) 263 | case expr.value 264 | when Num,Var, Tr, Fa then "#{expr.value.value}" 265 | when Str then "#{expr.value.value.inspect}" 266 | when Do then "#{expr.value[0].list.map{|x| (" "*(indent * 4)) + output(x, indent)}.join(";\n")}" 267 | when Fn then "(function(#{expr.value[0].list.map{|x| output x, indent}.join(',')}){\n#{output Expr[expr.value[1]], indent + 1}\n#{" "*((indent)* 4)}})" 268 | when Block then "{\n#{output Expr[expr.value[1]], indent + 1}\n#{" "*((indent)* 4)}}" 269 | when FCall then "#{output expr.value[0], indent}(#{expr.value[1].list.map{|x|output x, indent}.join(',')})" 270 | when UExpr then "#{expr.value[0].value.value} #{output expr.value[1], indent}" 271 | when BExpr then "#{output expr.value[1], indent}#{expr.value[0].value.value}#{output expr.value[2], indent}" 272 | when Ret then "return #{output expr.value[0], indent}" 273 | when PExpr then "(#{output expr.value[0], indent})" 274 | when Lam then output Expr.fun(&expr.value.value), indent 275 | when Arr then "[" + expr.value.list.map{|x| output x, indent}.join(",") + "]" 276 | when Break then "break" 277 | when Continue then "continue" 278 | when Index then 279 | expr.value.match(Index){|l, r| 280 | return "#{output l, indent+1}[#{output r,indent+1}]" 281 | } 282 | when For then 283 | expr.value.match(For) do |expr1, expr2, expr3, bl| 284 | return "for(#{output expr1, indent+1};#{output expr2, indent+1};#{output expr3, indent+1})#{output Expr[bl], indent + 1}" 285 | end 286 | when If then 287 | a = "if(#{output expr.value[0], indent + 1}) #{output Expr[expr.value[1]], indent + 1}" 288 | expr.value[2].value.match(Angen::RootClass::N){ 289 | }.match(Block){|arg, dost| 290 | a << "\n#{" "*(indent * 4)}else #{output Expr[Block.unchecked(arg, dost)], indent + 1}" 291 | } 292 | 293 | a 294 | 295 | when OpenClass then 296 | klass = expr.value.value 297 | dummy = klass.new 298 | met = klass.instance_methods(false) 299 | name = klass.instance_eval{@name || to_s.split("::").last} 300 | "#{" "*(indent * 4)}var #{name} = #{name} || (function(){});\n" + 301 | met.map{|x| 302 | output(Expr[:"#{name}.prototype.#{x}"].assign( 303 | Expr.fun(&klass.instance_method(x).bind(dummy)) 304 | ), indent + 1) 305 | }.join(";\n") 306 | else expr.value.output indent 307 | end 308 | end 309 | 310 | class VarA 311 | def output(indent = 0) 312 | match(VarA){|var, expr| 313 | return "var #{var.value} = #{JS.output expr, indent}" 314 | } 315 | end 316 | end 317 | 318 | class Local 319 | def [](sym) 320 | Expr[Var[sym]] 321 | end 322 | def []=(sym, exp) 323 | Expr[VarA[sym, Expr[exp]]] 324 | end 325 | end 326 | 327 | def self.local 328 | Local.new 329 | end 330 | 331 | class MyIdentity < Angen::MonadicEnv::StatementEnv 332 | def lift(x) 333 | Expr[x] 334 | end 335 | def rewrite(a) 336 | a.match(Lam){|l| 337 | return Expr.fun(&l.value).rewrite(&method(:rewrite)) 338 | }.match(Statements){|u| 339 | if !(Ret === u[-1].value) 340 | u[-1] = Expr[Ret.unchecked(u[-1])] 341 | end 342 | return u 343 | }.match(Block) {|arg, blk| 344 | r = blk[0].list 345 | while Ret === r[-1].value 346 | r[-1] = r[-1].value[0] 347 | end 348 | return Block.unchecked(arg, blk) 349 | } 350 | a 351 | end 352 | end 353 | 354 | class Global 355 | def self.[]=(sym, a) 356 | Unbind[Expr[Extract[sym]].assign(Extract[a])] 357 | end 358 | def initialize(path) 359 | @path = path 360 | end 361 | 362 | end 363 | 364 | def self.run(&b) 365 | u = MyIdentity.new 366 | ";" + output(u.rewrite(Expr[Lam[b]]), 0) + "();" 367 | end 368 | 369 | def self.tree(&b) 370 | u = MyIdentity.new 371 | u.rewrite(Expr[Lam[b]]) 372 | end 373 | 374 | window = Var[:'window'] 375 | class JSEnumerator 376 | def initialize(a) 377 | @a = a 378 | end 379 | def select(&b) 380 | JSEnumerator.new(lambda{|f| @a.call( 381 | lambda{|u| Expr.if(Expr[Extract[b.call(Extract[u])]]) {f.call u }} 382 | )}) 383 | end 384 | def take_while(&b) 385 | JSEnumerator.new(lambda{|f| @a.call( 386 | lambda{|u| Expr.if(Expr[Extract[b.call(Extract[u])]]) {f.call u }.else{ Unbind[Break.unchecked()] }} 387 | )}) 388 | end 389 | def map(&b) 390 | JSEnumerator.new(lambda{|f| @a.call( 391 | lambda{|u| f.call(Expr[Extract[b.call(Extract[u])]]) } 392 | )}) 393 | end 394 | def drop_while(&b) 395 | JSEnumerator.new(lambda{|f| @a.call( 396 | lambda{|u| Expr.if(Expr[Extract[b.call(Extract[u])]]) {Unbind[Continue.unchecked()] }.else{ f.call u }} 397 | )}) 398 | end 399 | def reduce(init = nil, &b) 400 | if init 401 | result = Var.let init 402 | each{|v| 403 | result.assign(b.call(result, v)) 404 | } 405 | result 406 | else 407 | first = Var.let :true 408 | result = Var.let :null 409 | each{|v| 410 | Expr.if(first) { 411 | result.assign(v) 412 | first.assign(:false) 413 | }.else{ 414 | result.assign(b.call(result, v)) 415 | } 416 | } 417 | result 418 | end 419 | end 420 | 421 | def index(a = nil, &bl) 422 | result = Var.let 0 423 | each do |b| 424 | Expr.if(bl ? bl.call(b) : b == a) { 425 | Unbind[Break.unchecked()] 426 | } .else { 427 | result.assign(result + 1) 428 | } 429 | end 430 | result 431 | end 432 | 433 | def count(a = nil, &bl) 434 | result = Var.let 0 435 | each do |b| 436 | Expr.if(bl ? bl.call(b) : b == a) { 437 | result.assign(result + 1) 438 | } 439 | end 440 | result 441 | end 442 | 443 | def all?(&bl) 444 | result = Var.let :true 445 | each do |b| 446 | Expr.if(bl.call(b).not) {result.assign :false; Unbind[Break.unchecked()]} 447 | end 448 | result 449 | end 450 | 451 | def any?(&bl) 452 | result = Var.let :false 453 | each do |b| 454 | Expr.if(bl.call(b).not) {result.assign :true; Unbind[Break.unchecked()]} 455 | end 456 | result 457 | end 458 | 459 | 460 | def each(&b) 461 | @a.call(b) 462 | end 463 | end 464 | 465 | def self.range(a, b) 466 | JSEnumerator.new(lambda{|f| Expr.for(var = Var.let(a), var < b, var.assign(var + 1)) do f.call(var) end }) 467 | end 468 | 469 | def self.iterate(a, b) 470 | JSEnumerator.new(lambda{|f| Expr.for(var = Var.let(a), Expr[:true], var.assign(b.call(var))) do f.call(var) end }) 471 | end 472 | 473 | 474 | def self.R(a) 475 | JSEnumerator.new(lambda{|f| arr = Var.let(a); Expr.for(var = Var.let(0), var < arr[:length], var.assign(var + 1)) do f.call(arr.index(var)) end }) 476 | end 477 | 478 | def self.import(sym) 479 | (class << self; self; end).send :define_method, sym do |*a| 480 | Expr[sym].call(*a) 481 | end 482 | end 483 | 484 | 485 | puts run { 486 | # words = R(["looks", "feels", "acts"]) 487 | # words.each{|w| 488 | # Console.log w + " like Ruby" 489 | # } 490 | words = Var.let ["looks", "feels", "acts"], :words 491 | words.forEach{|w| Console.log w + " like Ruby"} 492 | Unbind[:undefined] 493 | } 494 | =begin 495 | extend Angen::Translate 496 | a = %{ 497 | a = 3 498 | b = 5 499 | console.log a + b 500 | console.log "Hello world" 501 | console.log "Hello world1" 502 | } 503 | # p Ripper.sexp(a) 504 | puts output translate(a){|name, *args| 505 | case name 506 | when :program then Expr[Fn.unchecked([], Do[Statements[args[0]]])] 507 | when :command_call then FCall[Expr[BExpr[:".", args[0], args[2]]], args[3]] 508 | when :vcall then args[0] 509 | when :@ident then Var[args[0].to_sym] 510 | when :args_add_block then ArgList[args[0]] 511 | when :string_literal then args[0] 512 | when :string_content then args[0] 513 | when :@tstring_content then Str[args[0]] 514 | when :assign then VarA[args[0], args[1]] 515 | when :var_field then args[0] 516 | when :binary then BExpr[args[1], args[0], args[2]] 517 | when :var_ref then args[0] 518 | when :@int then Num[args[0].to_i] 519 | else name 520 | end 521 | },0 522 | =end 523 | 524 | 525 | end -------------------------------------------------------------------------------- /angen/angen.rb: -------------------------------------------------------------------------------- 1 | module Angen 2 | Options = {:msg => '', :opt => ''} 3 | class RootClass 4 | def self.[](*a) 5 | new(*a) 6 | end 7 | if Options[:opt] 8 | def raise(*) 9 | super() 10 | end 11 | end 12 | def self.===(*rhs) 13 | return true if rhs.length == 1 && rhs[0].class == self 14 | begin 15 | new(*rhs) 16 | true 17 | rescue 18 | false 19 | end 20 | end 21 | def self.| rhs 22 | (Angen.U [self]) | rhs 23 | end 24 | # ultrin 25 | class N < self 26 | def initialize(*rhs, &b) 27 | if !(rhs.size == 0 && !block_given? || rhs.size == 1 && rhs[0].class == N && !block_given?) 28 | raise (Options[:msg] || "Null type has value") 29 | end 30 | end 31 | def self.hash 32 | [:N].hash 33 | end 34 | define_method(:rewrite) do |&b| 35 | b.call(self) 36 | end 37 | def to_a 38 | [] 39 | end 40 | define_method(:match) do |rhs, &b| 41 | if self.class == rhs 42 | b.call 43 | end 44 | self 45 | end 46 | (class << self; self; end).send(:define_method, :parse) do |str, &b| 47 | [[N[], str]] 48 | end 49 | (class << self; self; end).send(:define_method,:gen) do |&b| 50 | self[] 51 | end 52 | def realtype 53 | self.class 54 | end 55 | 56 | end 57 | 58 | class T < self 59 | class << self 60 | attr_accessor :typelist, :namelist 61 | end 62 | end 63 | 64 | 65 | class A < self 66 | class << self 67 | attr_accessor :typelist, :namelist 68 | end 69 | end 70 | 71 | class I < self 72 | class << self 73 | attr_accessor :type 74 | end 75 | end 76 | class L < self 77 | class << self 78 | attr_accessor :type 79 | end 80 | end 81 | class U < self 82 | class << self 83 | attr_accessor :types 84 | end 85 | end 86 | class R < self 87 | class << self 88 | attr_accessor :outer, :name 89 | end 90 | end 91 | end 92 | extend self 93 | def T(typelist, namelist = nil, explicit = false) 94 | namelist ||= (0...typelist.size).map{|i| "_#{i}"} 95 | t = lambda{|*a| T *a} 96 | Class.new RootClass::T do 97 | def self.hash 98 | [:T, *typelist].hash 99 | end 100 | def self.eql?(rhs) 101 | (rhs <= RootClass::T) && rhs.typelist.zip(self.typelist).all?{|(a, b)|a.eql?(b)} 102 | end 103 | self.typelist = typelist 104 | self.namelist = namelist 105 | if Options[:opt] 106 | def self.to_s; ''; end 107 | def to_s; ''; end 108 | else 109 | def self.to_s 110 | super['#'] ? 111 | "(#{typelist.map{|x| x.to_s}.join(",")})" : 112 | super 113 | end 114 | define_method(:to_s) do 115 | "#{self.class}[#{namelist.map{|x| send(x)}.join(",")}]" 116 | end 117 | end 118 | 119 | define_method(:to_a) do 120 | [self.class] + namelist.map{|x| send(x).to_a} 121 | end 122 | attr_reader *namelist 123 | typelist.zip(namelist).each{|v| 124 | type, name = v 125 | define_method(:"#{name}=") do |rhs| 126 | raise (Options[:msg] || TypeError.new("#{name} #{rhs} is not a #{type} in #{self}")) if !(type === rhs) 127 | instance_variable_set(:"@#{name}", type[rhs]) 128 | end 129 | } 130 | define_method(:initialize) do |*rhs| 131 | if rhs.length == 1 && rhs[0].class == self.class 132 | namelist.each{|x| instance_variable_set(:"@#{x}", rhs[0].send(x))} 133 | return 134 | end 135 | raise (Options[:msg] || ArgumentError.new("Can't implicit making struct when explicit is set, #{self.class}")) if explicit 136 | raise (Options[:msg] || ArgumentError.new("Wrong number of Arguments #{self.class.to_s} #{rhs.length} #{typelist.length}")) if rhs.length != typelist.length 137 | rhs.each_with_index{|x, i| 138 | raise (Options[:msg] || TypeError.new( "#{namelist[i]} #{rhs} is not a #{typelist[i]} in #{self}")) if !(typelist[i] === x) 139 | } 140 | rhs.each_with_index{|x, i| 141 | self.send("#{namelist[i]}=", x) 142 | } 143 | end 144 | (class << self; self; end).send :define_method, :unchecked do |*rhs| 145 | allocate.instance_eval do 146 | rhs.each_with_index{|x, i| 147 | self.send("#{namelist[i]}=", x) 148 | } 149 | self 150 | end 151 | end 152 | define_method(:[]) do |i| 153 | self.send("#{namelist[i]}") 154 | end 155 | define_method(:[]=) do |i, a| 156 | self.send("#{namelist[i]}=", a) 157 | end 158 | define_method(:rewrite) do |&b| 159 | b.call(self.class.unchecked(*namelist.map{|i|send(i).rewrite(&b) })) 160 | end 161 | 162 | define_method(:match) do |rhs, &b| 163 | if self.class == rhs 164 | b.call(*namelist.map{|i| send(i) }) 165 | end 166 | self 167 | end 168 | define_method(:all) do 169 | namelist.map{|i| send(i) } 170 | end 171 | 172 | 173 | (class << self; self; end).send(:define_method,:gen) do |&b| 174 | self[*typelist.map{|x| x.gen(&b)}] 175 | end 176 | 177 | 178 | define_method(:realtype) do 179 | t.call(namelist.map{|x| send(x)}.map(&:realtype)) 180 | end 181 | 182 | (class << self; self; end).send(:define_method, :parse) do |str, &b| 183 | r = [[[], str]] 184 | typelist.each{|x| 185 | r = r.flat_map{|lastmatch| 186 | obj, str = lastmatch 187 | u = x.parse(str, &b) 188 | u.map{|newmatch| 189 | [obj + (newmatch[0].is_a?(Array) ? newmatch[0] : [newmatch[0]]), newmatch[1]] 190 | } 191 | } 192 | } 193 | r.map{|x| [self[*x[0]], x[1] ]} 194 | end 195 | end 196 | end 197 | 198 | def A(typelist, namelist = nil, explicit = false) 199 | namelist ||= (0...typelist.size).map{|i| "_#{i}"} 200 | t = lambda{|*a| T *a} 201 | Class.new RootClass::T do 202 | def self.hash 203 | [:A, *typelist].hash 204 | end 205 | def self.eql?(rhs) 206 | (rhs <= RootClass::T) && rhs.typelist.zip(self.typelist).all?{|(a, b)|a.eql?(b)} 207 | end 208 | self.typelist = typelist 209 | self.namelist = namelist 210 | if Options[:opt] 211 | def self.to_s; ''; end 212 | def to_s; ''; end 213 | else 214 | def self.to_s 215 | super['#'] ? 216 | "(@(#{typelist.map{|x| x.to_s}.join(",")})" : 217 | super 218 | end 219 | define_method(:to_s) do 220 | "#{self.class}[#{namelist.map{|x| send(x)}.join(",")}]" 221 | end 222 | end 223 | define_method(:to_a) do 224 | [self.class] + namelist.map{|x| send(x).to_a} 225 | end 226 | attr_reader *namelist 227 | typelist.zip(namelist).each{|v| 228 | type, name = v 229 | define_method(:"#{name}=") do |rhs| 230 | raise (Options[:msg] || TypeError.new("#{name} #{rhs} is not a #{type} in #{self}")) if !(type === rhs) 231 | instance_variable_set(:"@#{name}", type[rhs]) 232 | end 233 | } 234 | define_method(:initialize) do |rhs| 235 | if rhs.class == self.class 236 | namelist.each{|x| 237 | self.send("#{x}=", rhs.send(x)) 238 | } 239 | return 240 | end 241 | raise (Options[:msg] || ArgumentError.new("Wrong number of Arguments #{self.class.to_s} #{rhs.length} #{typelist.length}")) if (rhs.length != typelist.length) 242 | raise (Options[:msg] || ArgumentError.new("Can't implicit making struct when explicit is set, #{self.class}")) if explicit 243 | rhs.each_with_index{|x, i| 244 | raise (Options[:msg] || TypeError.new("#{namelist[i]} #{rhs} is not a #{typelist[i]} in #{self}")) if !(typelist[i] === x) 245 | } 246 | rhs.each_with_index{|x, i| 247 | self.send("#{namelist[i]}=", x) 248 | } 249 | 250 | end 251 | (class << self; self; end).send :define_method, :unchecked do |*rhs| 252 | allocate.instance_eval do 253 | rhs.each_with_index{|x, i| 254 | self.send("#{namelist[i]}=", x) 255 | } 256 | self 257 | end 258 | end 259 | define_method(:[]) do |i| 260 | self.send("#{namelist[i]}") 261 | end 262 | define_method(:[]=) do |i, a| 263 | self.send("#{namelist[i]}=", a) 264 | end 265 | define_method(:rewrite) do |&b| 266 | b.call(self.class.unchecked(*namelist.map{|i|send(i).rewrite(&b) })) 267 | end 268 | 269 | define_method(:match) do |rhs, &b| 270 | if self.class == rhs 271 | b.call(*namelist.map{|i| send(i) }) 272 | end 273 | self 274 | end 275 | 276 | define_method(:all) do 277 | namelist.map{|i| send(i) } 278 | end 279 | 280 | (class << self; self; end).send(:define_method,:gen) do |&b| 281 | self[*typelist.map{|x| x.gen(&b)}] 282 | end 283 | 284 | 285 | define_method(:realtype) do 286 | t.call(namelist.map{|x| send(x)}.map(&:realtype)) 287 | end 288 | 289 | (class << self; self; end).send(:define_method, :parse) do |str, &b| 290 | r = [[[], str]] 291 | typelist.each{|x| 292 | r = r.flat_map{|lastmatch| 293 | obj, str = lastmatch 294 | u = x.parse(str, &b) 295 | u.map{|newmatch| 296 | [obj + (newmatch[0].is_a?(Array) ? newmatch[0] : [newmatch[0]]), newmatch[1]] 297 | } 298 | } 299 | } 300 | r.map{|x| [self[*x[0]], x[1] ]} 301 | end 302 | end 303 | end 304 | def L(type) 305 | l = lambda{|a| L a} 306 | Class.new RootClass::L do 307 | self.type = type 308 | def self.hash 309 | [:L, type].hash 310 | end 311 | attr_accessor :list 312 | attr_accessor :type 313 | if Options[:opt] 314 | def self.to_s; ''; end 315 | def to_s; ''; end 316 | else 317 | def to_s 318 | "#{self.class}[#{self.list.join(",")}]" 319 | end 320 | def self.to_s 321 | super['#'] ? 322 | "[#{self.type.to_s}]" : 323 | super 324 | end 325 | end 326 | def to_a 327 | [self.class] + self.list.map{|x| x.to_a} 328 | end 329 | define_method(:initialize) do |rhs| 330 | if rhs.class == self.class 331 | self.list = rhs.list[0..-1] 332 | return 333 | end 334 | raise (Options[:msg] || TypeError.new("Not an array for #{rhs.inspect} in #{self.class}")) if !(Array === rhs) 335 | rhs.each_with_index{|x, i| 336 | raise (Options[:msg] || TypeError.new("#{type} mismatched #{x.class} #{Array === x ? x : ''} for #{self.class}")) if !(type === x) 337 | } 338 | self.list = [] 339 | self.type = type 340 | self.list = rhs.map{|x| type.new(x) } 341 | end 342 | (class << self; self; end).send :define_method, :unchecked do |*rhs| 343 | allocate.instance_eval do 344 | self.type = type 345 | self.list = rhs.map{|x| type.new(x) } 346 | self 347 | end 348 | end 349 | define_method(:match) do |rhs, &b| 350 | if self.class == rhs 351 | b.call(list) 352 | end 353 | self 354 | end 355 | define_method(:rewrite) do |&b| 356 | b.call(self.class[self.list.map{|x| x.rewrite(&b)}]) 357 | end 358 | def [](i) 359 | self.list[i] 360 | end 361 | (class << self; self; end).send(:define_method, :parse) do |str, &b| 362 | r = [[[], str]] 363 | loop do 364 | found = true 365 | s = r.flat_map{|lastmatch| 366 | obj, str = lastmatch 367 | u = type.parse(str, &b) 368 | found = false if u == [] 369 | u.map{|newmatch| 370 | [obj + (newmatch[0].is_a?(Array) ? newmatch[0] : [newmatch[0]]), newmatch[1]] 371 | } 372 | } 373 | break if !found 374 | r.concat s 375 | end 376 | r.map{|x| [self[x[0]], x[1]]} 377 | end 378 | (class << self; self; end).send(:define_method,:gen) do |&b| 379 | self[b.call(self)] 380 | end 381 | define_method(:realtype) do 382 | l.call list.map(&:realtype).uniq.inject(:|) 383 | end 384 | def self.eql?(rhs) 385 | (rhs <= RootClass::L) && self.type.eql?(rhs.type) 386 | end 387 | end 388 | end 389 | 390 | def I(type) 391 | ii = lambda{|a| I type} 392 | Class.new RootClass::I do 393 | self.type = type 394 | def self.hash 395 | [:I, type].hash 396 | end 397 | attr_accessor :type, :value 398 | def self.eql?(rhs) 399 | (rhs <= RootClass::I) && self.type.eql?(rhs.type) 400 | end 401 | if Options[:opt] 402 | def self.to_s; ''; end 403 | def to_s; ''; end 404 | else 405 | def to_s 406 | "#{self.class.to_s}[#{@value}]" 407 | end 408 | 409 | def self.to_s 410 | super['#'] ? 411 | "#{self.type.to_s}" : 412 | super 413 | end 414 | end 415 | def to_a 416 | [@value] 417 | end 418 | define_method(:match) do |rhs, &b| 419 | if self.type == rhs 420 | b.call(self.value) 421 | elsif self.class == rhs 422 | b.call(self) 423 | elsif rhs === self 424 | b.call(self) 425 | end 426 | self 427 | end 428 | define_method(:rewrite) do |&b| 429 | b.call(self) 430 | end 431 | define_method(:initialize) do |rhs| 432 | if rhs.is_a?(RootClass::I) && type === rhs.value 433 | self.type = type 434 | self.value = rhs.value 435 | return 436 | end 437 | if type === rhs 438 | self.type = type 439 | self.value = rhs 440 | return 441 | end 442 | raise (Options[:msg] || TypeError.new("#{rhs.class} is not #{type}")) 443 | end 444 | (class << self; self; end).send(:define_method, :parse) do |str, &b| 445 | b[str, self].map{|x| [self[x[0]], x[1]]} 446 | end 447 | (class << self; self; end).send(:define_method,:gen) do |&b| 448 | self[b.call(self)] 449 | end 450 | define_method(:realtype) do 451 | self.class 452 | end 453 | end 454 | end 455 | def R(outer, name) 456 | Class.new RootClass::R do 457 | self.outer = outer 458 | self.name = name 459 | def self.to_s 460 | "R #{outer.to_s} #{name}" 461 | end 462 | (class << self; self; end).send :define_method, :new do |*rhs| 463 | outer.const_get(name).new(*rhs) 464 | end 465 | (class << self; self; end).send :define_method, :[] do |*rhs| 466 | self.new(*rhs) 467 | end 468 | (class << self; self; end).send :define_method, :=== do |*rhs| 469 | outer.const_get(name).=== *rhs 470 | end 471 | (class << self; self; end).send(:define_method, :parse) do |str, &b| 472 | outer.const_get(name).parse(str, &b) 473 | end 474 | (class << self; self; end).send(:define_method, :gen) do |&b| 475 | outer.const_get(name).gen(&b) 476 | end 477 | end 478 | end 479 | 480 | def U(types) 481 | Class.new RootClass::U do 482 | self.types = types 483 | def to_s 484 | "#{self.class.to_s}[#{@value}]" 485 | end 486 | def to_a 487 | @value.to_a 488 | end 489 | if Options[:opt] 490 | def self.to_s; ''; end 491 | def to_s; ''; end 492 | else 493 | def self.to_s 494 | super['#'] ? 495 | "#{self.types.map{|x| x.to_s}.join(" | ")}" : 496 | super 497 | end 498 | def to_s 499 | "#{self.class.to_s}[#{@value}]" 500 | end 501 | end 502 | define_method(:match) do |rhs, &b| 503 | @value.match(rhs, &b) 504 | self 505 | end 506 | 507 | attr_accessor :type, :value 508 | define_method(:rewrite) do |&b| 509 | self.class[@value.rewrite(&b)] 510 | end 511 | (class << self; self; end).send :define_method, :deduce do |rhs| 512 | types.each{|t| 513 | begin 514 | t === rhs 515 | return t 516 | rescue 517 | 518 | end 519 | } 520 | end 521 | const_set :CACHE, {} 522 | define_method(:initialize) do |rhs| 523 | if rhs.class == self.class 524 | @type = rhs.type 525 | @value = rhs.value 526 | return 527 | end 528 | types.each{|t| 529 | if t == rhs.class 530 | @type = t 531 | @value = rhs 532 | return 533 | end 534 | } 535 | types.each{|t| 536 | if t <= RootClass::I && t === rhs 537 | @type = t 538 | @value = t.new(rhs) 539 | return 540 | end 541 | } 542 | types.each{|t| 543 | begin 544 | @type = t 545 | @value = t.new(rhs) 546 | return 547 | rescue 548 | 549 | end 550 | } 551 | raise (Options[:msg] || TypeError.new("No such subtype #{rhs.inspect} in #{self.class}")) 552 | end 553 | (class << self; self; end).send :define_method, "|" do |rhs| 554 | case 555 | when rhs.is_a?(Array) then Angen.U types + rhs 556 | when rhs.is_a?(RootClass::U) then Angen.U types + rhs.types 557 | else Angen.U types + [rhs] 558 | end 559 | end 560 | (class << self; self; end).send(:define_method, :parse) do |str, &b| 561 | r = [[[], str]] 562 | s = [] 563 | types.each{|x| 564 | s.concat r.flat_map{|lastmatch| 565 | obj, str = lastmatch 566 | u = x.parse(str, &b) 567 | u.map{|newmatch| 568 | [obj + (newmatch[0].is_a?(Array) ? newmatch[0] : [newmatch[0]]), newmatch[1]] 569 | } 570 | } 571 | } 572 | s.map{|x| [self[*x[0]], x[1] ]} 573 | end 574 | (class << self; self; end).send(:define_method, :gen) do |&b| 575 | self[types.sample.gen(&b)] 576 | end 577 | 578 | define_method(:realtype) do 579 | self.value.realtype 580 | end 581 | def self.eql?(rhs) 582 | (rhs <= RootClass::U) && self.types.sort.eql?(rhs.types.sort) 583 | end 584 | def self.hash 585 | [:U, self.types].hash 586 | end 587 | end 588 | end 589 | 590 | class CTor 591 | def initialize(obj) 592 | @obj = obj 593 | end 594 | def method_missing(sym, *args) 595 | @obj.const_set(sym, Angen.T(args)) 596 | end 597 | end 598 | 599 | class CTorE 600 | def initialize(obj) 601 | @obj = obj 602 | end 603 | def method_missing(sym, *args) 604 | @obj.const_set(sym, Angen.T(args, nil, true)) 605 | end 606 | end 607 | 608 | class CTorA 609 | def initialize(obj) 610 | @obj = obj 611 | end 612 | def method_missing(sym, *args) 613 | @obj.const_set(sym, Angen.A(args)) 614 | end 615 | end 616 | 617 | class Type 618 | def initialize(obj) 619 | @obj = obj 620 | end 621 | def method_missing(sym, *args) 622 | @obj.const_set(sym, Angen.I(*args)) 623 | end 624 | end 625 | 626 | class Rec 627 | def initialize(obj) 628 | @obj = obj 629 | end 630 | def method_missing(sym, *args) 631 | Angen.R(@obj, sym) 632 | end 633 | end 634 | 635 | class List 636 | def initialize(obj) 637 | @obj = obj 638 | end 639 | def method_missing(sym, *args) 640 | @obj.const_set(sym, Angen.L(*args)) 641 | end 642 | end 643 | 644 | 645 | class Optional 646 | def initialize(obj) 647 | @obj = obj 648 | end 649 | def method_missing(sym, arg) 650 | @obj.const_set(sym, arg | Angen::RootClass::N) 651 | end 652 | end 653 | 654 | def ctor(pool = self) 655 | CTor.new pool 656 | end 657 | def ctore(pool = self) 658 | CTorE.new pool 659 | end 660 | def ctora(pool = self) 661 | CTorA.new pool 662 | end 663 | def type(pool = self) 664 | Type.new pool 665 | end 666 | def rec(pool = self) 667 | Rec.new pool 668 | end 669 | def list(pool = self) 670 | List.new pool 671 | end 672 | def optional(pool = self) 673 | Optional.new pool 674 | end 675 | end --------------------------------------------------------------------------------