astrapi 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/astrapi +9 -0
- data/doc/astrapi.html +149 -0
- data/lib/ast.rb +68 -0
- data/lib/checker.rb +61 -0
- data/lib/class_diagram_printer.rb +83 -0
- data/lib/code.rb +48 -0
- data/lib/compiler.rb +149 -0
- data/lib/dbg.rb +7 -0
- data/lib/dot_printer.rb +72 -0
- data/lib/indent.rb +19 -0
- data/lib/lexer.rb +152 -0
- data/lib/parser.rb +110 -0
- data/lib/pretty_printer.rb +68 -0
- data/lib/ruby_generator.rb +329 -0
- data/lib/template_ast_printer.rb +79 -0
- data/lib/template_code.rb +48 -0
- data/lib/template_compiler.rb +59 -0
- data/lib/template_indent.rb +19 -0
- data/lib/template_lexer.rb +139 -0
- data/lib/template_parser.rb +75 -0
- data/lib/template_pretty_printer.rb +46 -0
- data/lib/template_visitor.rb +18 -0
- data/lib/version.rb +3 -0
- data/lib/visitor.rb +53 -0
- data/tests/geometry.mm +32 -0
- metadata +72 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
require_relative 'indent'
|
2
|
+
require_relative 'code'
|
3
|
+
|
4
|
+
module <%=mm.name%>
|
5
|
+
|
6
|
+
class DotPrinter
|
7
|
+
|
8
|
+
include Indent
|
9
|
+
|
10
|
+
attr_accessor :code,:nodes_decl,:nodes_cnx
|
11
|
+
|
12
|
+
def print ast #entry method
|
13
|
+
@verbose=false
|
14
|
+
@nodes_decl=Code.new
|
15
|
+
@nodes_cnx=Code.new
|
16
|
+
@printed_cnx={} #Cosmetic ! to keep track of already printed cnx source->sink
|
17
|
+
@code=Code.new
|
18
|
+
code << "digraph G {"
|
19
|
+
code.indent=2
|
20
|
+
code << "ordering=out;"
|
21
|
+
code << "ranksep=.4;"
|
22
|
+
code << "bgcolor=\"lightgrey\";"
|
23
|
+
code.newline
|
24
|
+
code << "node [shape=box, fixedsize=false, fontsize=12, fontname=\"Helvetica-bold\", fontcolor=\"blue\""
|
25
|
+
code << " width=.25, height=.25, color=\"black\", fillcolor=\"white\", style=\"filled, solid, bold\"];"
|
26
|
+
code << "edge [arrowsize=.5, color=\"black\", style=\"bold\"]"
|
27
|
+
process(ast)
|
28
|
+
code << @nodes_decl
|
29
|
+
code << @nodes_cnx
|
30
|
+
code.indent=0
|
31
|
+
code << "}"
|
32
|
+
return code
|
33
|
+
end
|
34
|
+
|
35
|
+
def process node,level=0
|
36
|
+
id=node.object_id
|
37
|
+
if node.is_a? Token
|
38
|
+
sink="#{id}"
|
39
|
+
val=node.val
|
40
|
+
nodes_decl << "#{sink} [label=\"#{val}\",color=\"red\"]"
|
41
|
+
else
|
42
|
+
|
43
|
+
kname=node.class.name.split("::")[1]
|
44
|
+
id=node.object_id
|
45
|
+
nodes_decl << "#{id} [label=\"#{kname}\"]"
|
46
|
+
|
47
|
+
node.instance_variables.each{|vname|
|
48
|
+
ivar=node.instance_variable_get(vname)
|
49
|
+
vname=vname.to_s[1..-1]
|
50
|
+
case ivar
|
51
|
+
when Array
|
52
|
+
ivar.each_with_index{|e,idx|
|
53
|
+
sink=process(e,level+2)
|
54
|
+
@printed_cnx[id]||=[]
|
55
|
+
nodes_cnx << "#{id} -> #{sink} [label=\"#{vname}[#{idx}]\"]" if not @printed_cnx[id].include? sink
|
56
|
+
@printed_cnx[id] << sink
|
57
|
+
}
|
58
|
+
when Token
|
59
|
+
val=ivar.val
|
60
|
+
sink="#{ivar.object_id}"
|
61
|
+
nodes_decl << "#{sink} [label=\"#{val}\",color=\"red\"]"
|
62
|
+
@printed_cnx[id]||=[]
|
63
|
+
nodes_cnx << "#{id} -> #{sink} [label=\"#{vname}\"]" if not @printed_cnx[id].include? sink
|
64
|
+
@printed_cnx[id] << sink
|
65
|
+
when nil
|
66
|
+
else
|
67
|
+
sink=process(ivar,level+2)
|
68
|
+
@printed_cnx[id]||=[]
|
69
|
+
nodes_cnx << "#{id} -> #{sink} [label=\"#{vname}\"]" if not @printed_cnx[id].include? sink
|
70
|
+
@printed_cnx[id] << sink
|
71
|
+
end
|
72
|
+
|
73
|
+
}
|
74
|
+
end
|
75
|
+
return id
|
76
|
+
end
|
77
|
+
|
78
|
+
end #class
|
79
|
+
end #module
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Code
|
2
|
+
|
3
|
+
attr_accessor :indent,:code
|
4
|
+
|
5
|
+
def initialize indent=0
|
6
|
+
@code=[]
|
7
|
+
@indent=indent
|
8
|
+
end
|
9
|
+
|
10
|
+
def <<(str)
|
11
|
+
if str.is_a? Code
|
12
|
+
str.code.each do |line|
|
13
|
+
@code << " "*@indent+line
|
14
|
+
end
|
15
|
+
elsif str.is_a? Array
|
16
|
+
str.each do |kode|
|
17
|
+
@code << kode
|
18
|
+
end
|
19
|
+
elsif str.nil?
|
20
|
+
else
|
21
|
+
@code << " "*@indent+str
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def finalize dot=false
|
26
|
+
if dot
|
27
|
+
return @code.join('\n')
|
28
|
+
end
|
29
|
+
@code.join("\n") if @code.any?
|
30
|
+
end
|
31
|
+
|
32
|
+
def newline
|
33
|
+
@code << " "
|
34
|
+
end
|
35
|
+
|
36
|
+
def save_as filename,verbose=true,sep="\n"
|
37
|
+
str=self.finalize
|
38
|
+
File.open(filename,'w'){|f| f.puts(str)}
|
39
|
+
puts "saved code in file #{filename}" if verbose
|
40
|
+
return filename
|
41
|
+
end
|
42
|
+
|
43
|
+
def size
|
44
|
+
@code.size
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative '<%=mm.name.to_s.downcase%>_parser'
|
2
|
+
require_relative '<%=mm.name.to_s.downcase%>_pp'
|
3
|
+
require_relative '<%=mm.name.to_s.downcase%>_ast_printer'
|
4
|
+
require_relative '<%=mm.name.to_s.downcase%>_visitor'
|
5
|
+
|
6
|
+
module <%=mm.name%>
|
7
|
+
|
8
|
+
class Compiler
|
9
|
+
attr_accessor :ast
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
puts "<%=mm.name%> compiler"
|
13
|
+
end
|
14
|
+
|
15
|
+
def compile filename
|
16
|
+
@ast=parse(filename)
|
17
|
+
visit
|
18
|
+
pretty_print
|
19
|
+
dot_print
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse filename
|
23
|
+
@filename=filename
|
24
|
+
name,@suffix=filename.split("/").last.split(".")
|
25
|
+
@basename=File.basename(filename,"."+@suffix)
|
26
|
+
puts "==> parsing #{filename}"
|
27
|
+
<%=mm.name%>::Parser.new.parse(filename)
|
28
|
+
end
|
29
|
+
|
30
|
+
def visit
|
31
|
+
puts "==> dummy visit"
|
32
|
+
<%=mm.name%>::Visitor.new.visit(ast)
|
33
|
+
end
|
34
|
+
|
35
|
+
def pretty_print
|
36
|
+
target="#{@basename}_pp.#{@suffix}"
|
37
|
+
puts "==> pretty print to ............ #{target}"
|
38
|
+
code_str=<%=mm.name%>::PrettyPrinter.new.print(ast)
|
39
|
+
File.open("#{target}",'w'){|f| f.puts code_str}
|
40
|
+
end
|
41
|
+
|
42
|
+
def dot_print
|
43
|
+
target="#{@basename}.dot"
|
44
|
+
puts "==> generate dot for AST in .... #{target}"
|
45
|
+
code=<%=mm.name%>::DotPrinter.new.print(ast)
|
46
|
+
code.save_as(target,verbose=false)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if $PROGRAM_NAME == __FILE__
|
53
|
+
filename=ARGV[0]
|
54
|
+
raise "need a <%=mm.name%> file !" if filename.nil?
|
55
|
+
t1 = Time.now
|
56
|
+
<%=mm.name%>::Compiler.new.compile(filename)
|
57
|
+
t2 = Time.now
|
58
|
+
puts "compiled in : #{t2-t1} s"
|
59
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'strscan'
|
3
|
+
#require 'benchmark'
|
4
|
+
|
5
|
+
class Token
|
6
|
+
attr_accessor :kind,:val,:pos
|
7
|
+
def initialize tab
|
8
|
+
@kind,@val,@pos=*tab
|
9
|
+
end
|
10
|
+
|
11
|
+
def is_a? kind
|
12
|
+
case kind
|
13
|
+
when Symbol
|
14
|
+
return @kind==kind
|
15
|
+
when Array
|
16
|
+
for sym in kind
|
17
|
+
return true if @kind==sym
|
18
|
+
end
|
19
|
+
return false
|
20
|
+
when Class
|
21
|
+
return kind==Token
|
22
|
+
else
|
23
|
+
raise "wrong type for token test"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def accept dummy,args=nil
|
28
|
+
val
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module <%=mm.name%>
|
33
|
+
|
34
|
+
class Lexer
|
35
|
+
#................................................
|
36
|
+
NEWLINE = /[\n]/
|
37
|
+
SPACE = /[ \t]+/
|
38
|
+
#.............punctuation........................
|
39
|
+
LPAREN = /\A\(/
|
40
|
+
RPAREN = /\A\)/
|
41
|
+
COMMENT = /\A\#(.*)/
|
42
|
+
# .............M3E specific literals.............
|
43
|
+
IDENT = /\A[a-zA-Z]+[0-9a-zA-Z_]*/i
|
44
|
+
FLOAT = /\A[0-9]+\.[0-9]+/
|
45
|
+
FRAC = /\A[0-9]+\/[0-9]+/
|
46
|
+
INTEGER = /\A[0-9]+/
|
47
|
+
RANGE = /\A#{INTEGER}\.\.#{INTEGER}/
|
48
|
+
STRING = /\A\"(.*)\"/ # need to check!
|
49
|
+
NIL = /\Anil/
|
50
|
+
TRUE = /\A\true/
|
51
|
+
FALSE = /\Afalse/
|
52
|
+
#..............DSL keywords......................
|
53
|
+
<%=keywords_regexp%>
|
54
|
+
|
55
|
+
def initialize str=''
|
56
|
+
init(str)
|
57
|
+
end
|
58
|
+
|
59
|
+
def init str
|
60
|
+
@ss=StringScanner.new(str)
|
61
|
+
@line=0
|
62
|
+
end
|
63
|
+
|
64
|
+
def tokenize str
|
65
|
+
@tokens=[]
|
66
|
+
init(str)
|
67
|
+
until @ss.eos?
|
68
|
+
@tokens << next_token()
|
69
|
+
end
|
70
|
+
return @tokens[0..-2]
|
71
|
+
end
|
72
|
+
|
73
|
+
#next token can detect spaces length
|
74
|
+
def next_token
|
75
|
+
|
76
|
+
if @ss.bol?
|
77
|
+
@line+=1
|
78
|
+
@old_pos=@ss.pos
|
79
|
+
end
|
80
|
+
|
81
|
+
position=[@line,@ss.pos-@old_pos+1]
|
82
|
+
|
83
|
+
return :eos if @ss.eos?
|
84
|
+
|
85
|
+
case
|
86
|
+
when text = @ss.scan(NEWLINE)
|
87
|
+
next_token()
|
88
|
+
when text = @ss.scan(SPACE)
|
89
|
+
next_token()
|
90
|
+
when text = @ss.scan(LPAREN)
|
91
|
+
return Token.new [:lparen,text,position]
|
92
|
+
when text = @ss.scan(COMMENT)
|
93
|
+
return Token.new [:m3e_comment,text,position]
|
94
|
+
when text = @ss.scan(RPAREN)
|
95
|
+
return Token.new [:rparen,text,position]
|
96
|
+
when text = @ss.scan(FLOAT)
|
97
|
+
return Token.new [:float_lit,text,position]
|
98
|
+
when text = @ss.scan(FRAC)
|
99
|
+
return Token.new [:frac_lit,text,position]
|
100
|
+
when text = @ss.scan(RANGE)
|
101
|
+
return Token.new [:range_lit,text,position]
|
102
|
+
when text = @ss.scan(INTEGER)
|
103
|
+
return Token.new [:integer_lit,text,position]
|
104
|
+
when text = @ss.scan(STRING)
|
105
|
+
return Token.new [:string_lit,text,position]
|
106
|
+
when text = @ss.scan(FRAC)
|
107
|
+
return Token.new [:frac_lit,text,position]
|
108
|
+
when text = @ss.scan(IDENT)
|
109
|
+
case
|
110
|
+
<%=apply_regexp%>
|
111
|
+
when value = text.match(NIL)
|
112
|
+
return Token.new [:nil,text,position]
|
113
|
+
when value = text.match(TRUE)
|
114
|
+
return Token.new [:true,text,position]
|
115
|
+
when value = text.match(FALSE)
|
116
|
+
return Token.new [:false,text,position]
|
117
|
+
else
|
118
|
+
return Token.new [:identifier,text,position]
|
119
|
+
end
|
120
|
+
else
|
121
|
+
x = @ss.getch
|
122
|
+
return Token.new [x, x,position]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
if $PROGRAM_NAME == __FILE__
|
129
|
+
str=IO.read(ARGV[0])
|
130
|
+
#str.downcase!
|
131
|
+
puts str
|
132
|
+
t1 = Time.now
|
133
|
+
lexer=<%=mm.name%>::Lexer.new
|
134
|
+
tokens=lexer.tokenize(str)
|
135
|
+
t2 = Time.now
|
136
|
+
pp tokens
|
137
|
+
puts "number of tokens : #{tokens.size}"
|
138
|
+
puts "tokenized in : #{t2-t1} s"
|
139
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require_relative 'indent'
|
3
|
+
require_relative '<%=mm.name.to_s.downcase%>_lexer'
|
4
|
+
require_relative '<%=mm.name.to_s.downcase%>_ast'
|
5
|
+
|
6
|
+
module <%=mm.name%>
|
7
|
+
|
8
|
+
class Parser
|
9
|
+
include Indent #helper methods mixed in
|
10
|
+
|
11
|
+
attr_accessor :lexer,:tokens
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@verbose=false
|
15
|
+
@lexer=Lexer.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse filename
|
19
|
+
str=::IO.read(filename)
|
20
|
+
@tokens=lexer.tokenize(str)
|
21
|
+
last_pos = @tokens.last.pos
|
22
|
+
@tokens << Token.new([:eos,'',last_pos])
|
23
|
+
pp @tokens if @verbose
|
24
|
+
parse<%=mm.classes.first.name%>
|
25
|
+
end
|
26
|
+
|
27
|
+
def acceptIt
|
28
|
+
tok=tokens.shift
|
29
|
+
say "consuming #{tok.val} (#{tok.kind})"
|
30
|
+
tok
|
31
|
+
end
|
32
|
+
|
33
|
+
def showNext n=0
|
34
|
+
tokens[n]
|
35
|
+
end
|
36
|
+
|
37
|
+
def expect kind
|
38
|
+
if (actual=showNext.kind)!=kind
|
39
|
+
abort "ERROR at #{showNext.pos}. Expecting #{kind}. Got #{actual}"
|
40
|
+
else
|
41
|
+
return acceptIt()
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def nil_maybe?
|
46
|
+
if showNext.is_a?(:nil)
|
47
|
+
return acceptIt
|
48
|
+
else
|
49
|
+
return nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def parse_comments
|
54
|
+
ret=nil
|
55
|
+
while showNext.is_a? :m3e_comment
|
56
|
+
str||=""
|
57
|
+
str << acceptIt.val
|
58
|
+
end
|
59
|
+
if str
|
60
|
+
ret=Token.new([:comment,str,[0,0]])
|
61
|
+
end
|
62
|
+
ret
|
63
|
+
end
|
64
|
+
<%=parsing_methods%>
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
if $PROGRAM_NAME == __FILE__
|
69
|
+
filename=ARGV[0]
|
70
|
+
raise "need a file !" if filename.nil?
|
71
|
+
t1 = Time.now
|
72
|
+
<%=mm.name%>::Parser.new.parse(filename)
|
73
|
+
t2 = Time.now
|
74
|
+
puts "parsed in : #{t2-t1} s"
|
75
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require_relative '<%=mm.name.to_s.downcase%>_ast'
|
3
|
+
require_relative 'indent'
|
4
|
+
require_relative 'code'
|
5
|
+
|
6
|
+
module <%=mm.name%>
|
7
|
+
|
8
|
+
class PrettyPrinter
|
9
|
+
|
10
|
+
include Indent
|
11
|
+
|
12
|
+
def print ast
|
13
|
+
ary=ast.accept(self)
|
14
|
+
str=prpr(ary)
|
15
|
+
end
|
16
|
+
|
17
|
+
def prpr ary
|
18
|
+
print_rec(ary).lstrip
|
19
|
+
end
|
20
|
+
|
21
|
+
def print_rec ary,indent=0
|
22
|
+
str=""
|
23
|
+
case e=ary
|
24
|
+
when Array
|
25
|
+
str << "\n"
|
26
|
+
if e.first.to_s.start_with? "#"
|
27
|
+
str << " "*indent+ary.shift+"\n"
|
28
|
+
end
|
29
|
+
str << " "*indent+"("
|
30
|
+
ary.each do |e|
|
31
|
+
str << print_rec(e,indent+2)
|
32
|
+
end
|
33
|
+
if ary.last.is_a? Array
|
34
|
+
str << "\n"+" "*indent+")"
|
35
|
+
else
|
36
|
+
str<< "\b)"
|
37
|
+
end
|
38
|
+
else
|
39
|
+
str << e.to_s+ " "
|
40
|
+
end
|
41
|
+
return str
|
42
|
+
end
|
43
|
+
|
44
|
+
<%=visiting_methods%>
|
45
|
+
end #class
|
46
|
+
end #module
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative '<%=mm.name.to_s.downcase%>_ast'
|
2
|
+
require_relative 'indent'
|
3
|
+
require_relative 'code'
|
4
|
+
|
5
|
+
module <%=mm.name%>
|
6
|
+
|
7
|
+
class Visitor
|
8
|
+
|
9
|
+
include Indent
|
10
|
+
|
11
|
+
def visit ast
|
12
|
+
@verbose=true
|
13
|
+
ast.accept(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
<%=visiting_methods%>
|
17
|
+
end #class
|
18
|
+
end #module
|
data/lib/version.rb
ADDED
data/lib/visitor.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'ast'
|
2
|
+
require_relative 'indent'
|
3
|
+
require_relative 'code'
|
4
|
+
|
5
|
+
module Astrapi
|
6
|
+
|
7
|
+
class Visitor
|
8
|
+
|
9
|
+
include Indent
|
10
|
+
|
11
|
+
def visit ast
|
12
|
+
ast.accept(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def visitModule modul,args=nil
|
16
|
+
indent "visitModule"
|
17
|
+
name=modul.name.accept(self)
|
18
|
+
modul.classes.each{|k| k.accept(self)}
|
19
|
+
dedent
|
20
|
+
end
|
21
|
+
|
22
|
+
def visitKlass klass,args=nil
|
23
|
+
indent "visitKlass #{klass.name.sym}"
|
24
|
+
klass.inheritance.accept(self)
|
25
|
+
klass.attrs.each{|attr| attr.accept(self)}
|
26
|
+
dedent
|
27
|
+
end
|
28
|
+
|
29
|
+
def visitAttr attr,args=nil
|
30
|
+
indent "visitAttr"
|
31
|
+
attr.name.accept(self)
|
32
|
+
attr.type.accept(self)
|
33
|
+
dedent
|
34
|
+
end
|
35
|
+
|
36
|
+
def visitType type,args=nil
|
37
|
+
indent "visitType"
|
38
|
+
end
|
39
|
+
|
40
|
+
def visitArrayOf arrayOf,args=nil
|
41
|
+
indent "visitArrayOf"
|
42
|
+
arrayOf.type.accept(self)
|
43
|
+
dedent
|
44
|
+
end
|
45
|
+
|
46
|
+
def visitIdentifier id,args=nil
|
47
|
+
indent "visitIdentifier"
|
48
|
+
say " - #{id.sym}"
|
49
|
+
dedent
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
data/tests/geometry.mm
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Geometry
|
2
|
+
|
3
|
+
class Scene
|
4
|
+
attr name => IDENT
|
5
|
+
attr elements => Shape[]
|
6
|
+
end
|
7
|
+
|
8
|
+
class Shape
|
9
|
+
attr id => IDENT
|
10
|
+
attr position => Position
|
11
|
+
end
|
12
|
+
|
13
|
+
class Square < Shape
|
14
|
+
attr size => Size
|
15
|
+
end
|
16
|
+
|
17
|
+
class Circle < Shape
|
18
|
+
attr radius => Size
|
19
|
+
end
|
20
|
+
|
21
|
+
class Rectangle < Shape
|
22
|
+
attr size => Size
|
23
|
+
end
|
24
|
+
|
25
|
+
class Size
|
26
|
+
attr dims => INTEGER[]
|
27
|
+
end
|
28
|
+
|
29
|
+
class Position
|
30
|
+
attr coord => INTEGER[]
|
31
|
+
end
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: astrapi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jean-Christophe Le Lann
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-05-17 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Starting from the metamodel of a DSL (abstract classes and their relationship),
|
14
|
+
Astrapi generates a compiler front end for this DSL. The model itself is expressed
|
15
|
+
in S-expressions
|
16
|
+
email: lelannje@ensta-bretagne.fr
|
17
|
+
executables:
|
18
|
+
- astrapi
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- bin/astrapi
|
23
|
+
- doc/astrapi.html
|
24
|
+
- lib/ast.rb
|
25
|
+
- lib/checker.rb
|
26
|
+
- lib/class_diagram_printer.rb
|
27
|
+
- lib/code.rb
|
28
|
+
- lib/compiler.rb
|
29
|
+
- lib/dbg.rb
|
30
|
+
- lib/dot_printer.rb
|
31
|
+
- lib/indent.rb
|
32
|
+
- lib/lexer.rb
|
33
|
+
- lib/parser.rb
|
34
|
+
- lib/pretty_printer.rb
|
35
|
+
- lib/ruby_generator.rb
|
36
|
+
- lib/template_ast_printer.rb
|
37
|
+
- lib/template_code.rb
|
38
|
+
- lib/template_compiler.rb
|
39
|
+
- lib/template_indent.rb
|
40
|
+
- lib/template_lexer.rb
|
41
|
+
- lib/template_parser.rb
|
42
|
+
- lib/template_pretty_printer.rb
|
43
|
+
- lib/template_visitor.rb
|
44
|
+
- lib/version.rb
|
45
|
+
- lib/visitor.rb
|
46
|
+
- tests/geometry.mm
|
47
|
+
homepage: http://www.jcll.fr/astrapi.html
|
48
|
+
licenses:
|
49
|
+
- MIT
|
50
|
+
metadata: {}
|
51
|
+
post_install_message: Thanks for installing! A small doc & examples are in astrapi/doc
|
52
|
+
and astrapi/tests.
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 2.0.0
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 2.4.6
|
69
|
+
signing_key:
|
70
|
+
specification_version: 4
|
71
|
+
summary: meta-compiler for S-expression based Domain Specific Languages (DSL)
|
72
|
+
test_files: []
|