This commit is contained in:
vonhyou 2021-04-14 21:46:42 +08:00
parent 94599c5e4a
commit efd5b22761

View file

@ -15,9 +15,7 @@ end
def tokenize(program) def tokenize(program)
# Convert scripts to token lists # Convert scripts to token lists
replacements = { '(' => ' ( ', ')' => ' ) ' } program.gsub('(', ' ( ').gsub(')', ' ) ').split
program.gsub(Regexp.union(replacements.keys), replacements)
.split(' ')
end end
def make_list(tokens) def make_list(tokens)
@ -31,8 +29,7 @@ def read_tokens(tokens)
# read expressions from token # read expressions from token
raise SyntaxError, 'Unexpected EOF' if tokens.empty? raise SyntaxError, 'Unexpected EOF' if tokens.empty?
token = tokens.shift case token = tokens.shift
case token
when '(' when '('
make_list tokens make_list tokens
when ')' when ')'
@ -44,41 +41,37 @@ end
def atom(token) def atom(token)
# Analyse numbers and symbols # Analyse numbers and symbols
is_integer = ->(atom) { atom.match?(/^-?\d+$/) } case token
is_float = ->(atom) { atom.match?(/^(-?\d+)(\.\d+)?$/) } when /\d/
return Integer token if is_integer.call token (token.to_f % 1).positive? ? token.to_f : token.to_i
return Float token if is_float.call token else
token.to_sym
token.to_sym end
end end
##### Environments ##### Environments
def generate_env $global_env = {
lisp_env = { '+': ->(args) { args.sum }, # args.inject(0, :+)
'+': ->(args) { args.sum }, # args.inject(0, :+) '-': ->(*args) { eval args.join('-') },
'-': ->(*args) { eval args.join('-') }, '*': ->(*args) { eval args.join('*') },
'*': ->(*args) { eval args.join('*') }, '/': ->(*args) { eval args.join('/') },
'/': ->(*args) { eval args.join('/') }, '>': ->(args) { args[0] > args[1] },
'>': ->(args) { args[0] > args[1] }, '<': ->(args) { args[0] < args[1] },
'<': ->(args) { args[0] < args[1] }, '=': ->(args) { args[0] == args[1] },
'=': ->(args) { args[0] == args[1] }, '>=': ->(args) { args[0] >= args[1] },
'>=': ->(args) { args[0] >= args[1] }, '<=': ->(args) { args[0] <= args[1] },
'<=': ->(args) { args[0] <= args[1] }, 'min': ->(*args) { args.min },
'min': ->(*args) { args.min }, 'max': ->(*args) { args.max },
'max': ->(*args) { args.max }, 'car': ->(arr) { arr[0] },
'car': ->(arr) { arr[0] }, 'cdr': ->(arr) { arr[1..-1] },
'cdr': ->(arr) { arr[1..-1] }, 'cons': ->(arr) { arr },
'cons': ->(arr) { arr }, 'quote': ->(arr) { arr },
'quote': ->(arr) { arr }, 'print': ->(arg) { p arg },
'print': ->(arg) { p arg }, 'begin': ->(*_args) { true }
'begin': ->(*_args) { true } }
}
end
##### Lisp Eval ##### Lisp Eval
$global_env = generate_env
def lisp_eval(elem, env = $global_env) def lisp_eval(elem, env = $global_env)
if elem.instance_of? Symbol if elem.instance_of? Symbol
env[elem] env[elem]
@ -103,18 +96,17 @@ def lisp_eval(elem, env = $global_env)
end end
##### REPL ##### REPL
def repl(prompt = 'minlisp ƛ>> ')
def repl(prompt='minlisp ƛ>> ')
loop do loop do
print prompt print prompt
val = lisp_eval(parse(gets.chomp)) val = lisp_eval(parse(gets.chomp))
print_value val unless val.nil? print_value val unless val.nil? || val.instance_of?(Proc)
end end
end end
def print_value(value) def print_value(value)
puts ";Value: #{value.to_s}" puts ";Value: #{value}"
end end
repl() repl