-
Notifications
You must be signed in to change notification settings - Fork 95
/
minilisp.rb
94 lines (72 loc) · 2.13 KB
/
minilisp.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# Reproduces [1] using parslet.
# [1] http://thingsaaronmade.com/blog/a-quick-intro-to-writing-a-parser-using-treetop.html
$:.unshift File.dirname(__FILE__) + "/../lib"
require 'pp'
require 'parslet'
require 'parslet/convenience'
module MiniLisp
class Parser < Parslet::Parser
root :expression
rule(:expression) {
space? >> str('(') >> space? >> body >> str(')') >> space?
}
rule(:body) {
(expression | identifier | float | integer | string).repeat.as(:exp)
}
rule(:space) {
match('\s').repeat(1)
}
rule(:space?) {
space.maybe
}
rule(:identifier) {
(match('[a-zA-Z=*]') >> match('[a-zA-Z=*_]').repeat).as(:identifier) >> space?
}
rule(:float) {
(
integer >> (
str('.') >> match('[0-9]').repeat(1) |
str('e') >> match('[0-9]').repeat(1)
).as(:e)
).as(:float) >> space?
}
rule(:integer) {
((str('+') | str('-')).maybe >> match("[0-9]").repeat(1)).as(:integer) >> space?
}
rule(:string) {
str('"') >> (
str('\\') >> any |
str('"').absent? >> any
).repeat.as(:string) >> str('"') >> space?
}
end
class Transform
include Parslet
attr_reader :t
def initialize
@t = Parslet::Transform.new
# To understand these, take a look at what comes out of the parser.
t.rule(:identifier => simple(:ident)) { ident.to_sym }
t.rule(:string => simple(:str)) { str }
t.rule(:integer => simple(:int)) { Integer(int) }
t.rule(:float=>{:integer=> simple(:a), :e=> simple(:b)}) { Float(a + b) }
t.rule(:exp => subtree(:exp)) { exp }
end
def do(tree)
t.apply(tree)
end
end
end
parser = MiniLisp::Parser.new
transform = MiniLisp::Transform.new
result = parser.parse_with_debug %Q{
(define test (lambda ()
(begin
(display "something")
(display 1)
(display 3.08))))
}
# Transform the result
pp transform.do(result) if result
# Thereby reducing it to the earlier problem:
# http://github.com/kschiess/toylisp