-
Notifications
You must be signed in to change notification settings - Fork 0
lambda function #2
Copy link
Copy link
Open
Description
I tried to add the lambda function, code like below.
module main
import readline
import math
enum Proc {
plus min mul div mod lt cons car cdr list eq atom sin
}
enum TokenType {
nothing boolean integer float str token_list cons function
}
struct Token {
mut:
typ TokenType
boolean bool
integer int
float f64
stri string
function Proc
token_list []Token
}
struct Env {
mut:
define_nbr []string
define []Token
}
pub fn (t Token) str() string {
match t.typ {
.boolean { if t.boolean { return '#t' } else { return '#f' } }
.integer { return '$t.integer' }
.float { return '$t.float' }
.str { return '$t.stri' }
.token_list { return '$t.token_list' }
.cons { return '(${show_cons(t)})' }
else { return '' }
}
}
fn show_cons(t Token) string {
if t.token_list.len == 1 {
return '${t.token_list[0]}'
}
if t.token_list[1].typ == .token_list && t.token_list[1].token_list.len == 0 {
return '${t.token_list[0]}'
} else if t.token_list[1].typ == .cons {
return '${t.token_list[0]} ${show_cons(t.token_list[1])}'
} else {
return '${t.token_list[0]} . ${t.token_list[1].str()}'
}
}
fn plus(expr Token) Token {
mut res := 0.0
mut float := false
for tok in expr.token_list {
if tok.typ == .integer {
res += tok.integer
} else if tok.typ == .float {
res += tok.float
float = true
}
}
if !float {
return Token{typ: .integer, integer: int(res)}
} else {
return Token{typ: .float, float: res}
}
}
fn min(expr Token) Token {
mut res := 0.0
mut float := false
if expr.token_list.len == 1 {
if expr.token_list[0].typ == .integer {
res = -(expr.token_list[0].integer)
} else if expr.token_list[0].typ == .float {
res = -(expr.token_list[0].float)
float = true
}
} else {
if expr.token_list[0].typ == .integer {
res = expr.token_list[0].integer
} else if expr.token_list[0].typ == .float {
res = expr.token_list[0].float
float = true
}
expr_list := expr.token_list[1..]
for tok in expr_list {
if tok.typ == .integer {
res -= tok.integer
} else if tok.typ == .float {
res -= tok.float
float = true
}
}
}
if !float {
return Token{typ: .integer, integer: int(res)}
} else {
return Token{typ: .float, float: res}
}
}
fn mul(expr Token) Token {
mut res := 1.0
mut float := false
for tok in expr.token_list {
if tok.typ == .integer {
res *= tok.integer
} else if tok.typ == .float {
res *= tok.float
float = true
}
}
if !float {
return Token{typ: .integer, integer: int(res)}
} else {
return Token{typ: .float, float: res}
}
}
fn divi(expr Token) Token {
mut res := 0.0
if expr.token_list.len == 1 {
if expr.token_list[0].typ == .integer {
res = f32(1) / expr.token_list[0].integer
} else if expr.token_list[0].typ == .float {
res = f32(1) / expr.token_list[0].float
}
} else {
if expr.token_list[0].typ == .integer {
res = expr.token_list[0].integer
} else if expr.token_list[0].typ == .float {
res = expr.token_list[0].float
}
expr_list := expr.token_list[1..]
for tok in expr_list {
if tok.typ == .integer {
res /= tok.integer
} else if tok.typ == .float {
res /= tok.float
}
}
}
return Token{typ: .float, float: res}
}
fn mod(expr Token) Token {
a := if expr.token_list[0].typ == .integer {
expr.token_list[0].integer
} else {
int(expr.token_list[0].float) //Cant mod floats in v :(
}
b := if expr.token_list[1].typ == .integer {
expr.token_list[1].integer
} else {
int(expr.token_list[1].float) //Cant mod floats in v :(
}
return Token{typ: .integer, integer: a % b}
}
fn sin(expr Token) Token {
mut res := 0.0
a := if expr.token_list[0].typ == .integer {
expr.token_list[0].integer
} else {
int(expr.token_list[0].float)
}
res = math.sin(a)
return Token{typ: .float, float: res}
}
fn lt(expr Token) Token {
typ := expr.token_list[0].typ
mut res := false
if typ != expr.token_list[1].typ {
panic('Not the same typ on lt')
}
if typ == .boolean {
res = !expr.token_list[0].boolean && expr.token_list[1].boolean
}
if typ == .integer {
res = expr.token_list[0].integer < expr.token_list[1].integer
}
if typ == .float {
res = expr.token_list[0].float < expr.token_list[1].float
}
if typ == .str {
res = expr.token_list[0].stri < expr.token_list[1].stri
}
return Token{typ: .boolean, boolean: res}
}
fn cons(expr Token) Token {
return Token{typ: .cons, token_list: [expr.token_list[0], expr.token_list[1]]}
}
fn car(expr Token) Token {
return expr.token_list[0].token_list[0]
}
fn cdr(expr Token) Token {
to_take := expr.token_list[0]
if to_take.typ == .cons {
return to_take.token_list[1]
} else {
return Token{typ: to_take.typ, token_list: to_take.token_list[1..]}
}
}
fn list(expr Token) Token {
return Token{typ: .token_list, token_list: expr.token_list}
}
fn eq(expr Token) Token {
typ := expr.token_list[0].typ
mut res := false
if typ != expr.token_list[1].typ {
println('Not the same typ on eq')
return Token{typ: .nothing}
//panic('Not the same typ on eq')
}
else if typ == .boolean {
res = expr.token_list[0].boolean == expr.token_list[1].boolean
}
else if typ == .integer {
res = expr.token_list[0].integer == expr.token_list[1].integer
}
else if typ == .float {
res = expr.token_list[0].float == expr.token_list[1].float
}
else if typ == .str {
res = expr.token_list[0].stri == expr.token_list[1].stri
}
else if typ == .token_list {
res = expr.token_list[0].token_list == expr.token_list[1].token_list
}
return Token{typ: .boolean, boolean: res}
}
fn atom(expr Token) Token {
res := expr.token_list[0].typ != .token_list && expr.token_list[0].typ != .cons
return Token{typ: .boolean, boolean: res}
}
fn call_func(call Token, expr Token) Token {
match call.function {
.plus { return plus(expr) }
.min { return min(expr) }
.mul { return mul(expr) }
.div { return divi(expr) }
.mod { return mod(expr) }
.lt { return lt(expr) }
.cons { return cons(expr) }
.car { return car(expr) }
.cdr { return cdr(expr) }
.list { return list(expr) }
.eq { return eq(expr) }
.atom { return atom(expr) }
.sin { return sin(expr) }
// else { Token{typ: .nothing }}
}
return Token{typ: .str, stri: 'nothing'}
}
fn eval(expr Token, mut env Env) ?Token {
if expr.typ == .str {
for nbr := env.define_nbr.len-1; nbr >= 0; nbr-- {
if expr.stri == env.define_nbr[nbr] {
return env.define[nbr]
}
}
if expr.stri == '*env*' {
println('env: ${env}')
} else {
println('unknown $expr.stri')
}
return Token{typ: .nothing}
} else if expr.typ == .integer || expr.typ == .float || expr.typ == .boolean {
return expr
} else if expr.token_list.len >= 2 && expr.token_list[0].stri == 'quote' {
return expr.token_list[1]
} else if expr.token_list.len == 3 && expr.token_list[0].stri == 'define' {
v_vars := expr.token_list[1]
v_expr := expr.token_list[2]
env.define_nbr << v_vars.stri
if v_expr.typ == .token_list && v_expr.token_list[0].stri == 'lambda' {
env.define << v_expr
} else {
env.define << eval(v_expr, mut env) or { return err }
}
} else if expr.token_list.len >= 2 && expr.token_list[0].stri == 'cond' {
for i := 1; i < expr.token_list.len; i++ {
if expr.token_list[i].token_list.len < 2 {
println('cond list too small')
return Token{typ: .nothing}
}
res := eval(expr.token_list[i].token_list[0], mut env) or { return err }
if res.boolean {
return eval(expr.token_list[i].token_list[1], mut env)
}
}
} else if expr.token_list.len == 2 &&
expr.token_list[0].typ == .token_list &&
expr.token_list[0].token_list[0].stri == 'lambda' {
v_vars := expr.token_list[0].token_list[1]
v_expr := expr.token_list[0].token_list[2]
v_args := eval(expr.token_list[1], mut env) or { return err }
mut v_env := env
mut new_tok := Token{typ: .str, stri: 'nothing'}
for i := 0; i < v_vars.token_list.len; i++ {
match v_args.typ {
.token_list { new_tok = v_args.token_list[i] }
else { new_tok = v_args }
}
v_env.define_nbr << v_vars.token_list[i].stri
v_env.define << new_tok
}
return eval(v_expr, mut v_env)
} else {
if expr.token_list.len == 0 {
return Token{typ: .token_list, token_list: []}
}
call := eval(expr.token_list[0], mut env) or { return err }
if call.typ == .token_list && call.token_list[0].stri == 'lambda' {
mut new_tok := Token{typ: .token_list, token_list: []}
for i := 1; i < expr.token_list.len; i++ {
v_tok := eval(expr.token_list[i],mut env) or { return err }
new_tok.token_list << v_tok
}
mut v_args := Token{typ: .token_list, token_list: [Token{typ: .str, stri: 'quote'}, new_tok]} //須加quote開頭
v_expr := Token{typ: .token_list, token_list: [call, v_args]}
return eval(v_expr, mut env)
}
typ := if call.function == .cons { TokenType.cons } else { TokenType.token_list }
mut new_expr := Token{typ: typ, token_list: []}
for i := 1; i < expr.token_list.len; i++ {
new_tok := eval(expr.token_list[i],mut env) or { return err }
new_expr.token_list << new_tok
}
return call_func(call, new_expr)
}
return Token{typ: .nothing}
}
fn parse(mut expr []string) ?Token {
if expr.len <= 1 {
println('unexpected eof')
return Token{typ: .nothing}
}
mut tok := expr[0]
expr.delete(0)
match tok {
'#t' { return Token{typ: .boolean, boolean: true} }
'#f' { return Token{typ: .boolean, boolean: false} }
'null' { return Token{typ: .token_list, token_list: []} }
'\'' {
mut new_list := Token{typ: .token_list, token_list: [Token{typ: .str, stri: 'quote'}]}
new_expr := parse(mut expr) or { return err }
new_list.token_list << new_expr
return new_list
}
'(' {
mut new_list := Token{typ: .token_list, token_list: []} // new_list = []
for expr[0] != ')' {
new_expr := parse(mut expr) or { return err }
new_list.token_list << new_expr // new_list = [new_expr]
if expr.len == 1 {
println('unexpected eof')
return Token{typ: .nothing}
}
}
expr.delete(0)
return new_list
}
')' {
println('unexpected )')
return Token{typ: .nothing}
}
else {}
}
if tok[0].is_digit() {
if tok.contains('.') {
return Token{typ: .float, float: tok.f32()}
} else {
return Token{typ: .integer, integer: tok.int()}
}
}
return Token{typ: .str, stri: tok}
}
fn token(line string) [] string {
mut list := []string{}
mut str := ''
for c in line {
mut ch := c.ascii_str()
match ch {
'(',')','\'',' ' {
if str.len>0 {
list << str
str = ''
}
if ch != ' ' { list << ch }
}
else { str += ch }
}
}
if str != '' && str != '\n'{
list << str.replace('\n','')
}
return list
}
fn init_env() Env {
return Env{
define_nbr: [
'+',
'-',
'*',
'/',
'%',
'<',
'cons',
'car',
'cdr',
'list',
'eq?',
'atom?',
'sin'
]
define: [
Token{ typ: .function, function: .plus},
Token{ typ: .function, function: .min},
Token{ typ: .function, function: .mul},
Token{ typ: .function, function: .div},
Token{ typ: .function, function: .mod},
Token{ typ: .function, function: .lt},
Token{ typ: .function, function: .cons},
Token{ typ: .function, function: .car},
Token{ typ: .function, function: .cdr},
Token{ typ: .function, function: .list},
Token{ typ: .function, function: .eq},
Token{ typ: .function, function: .atom},
Token{ typ: .function, function: .sin}
]
}
}
fn repl(){
mut env := init_env()
mut rl := readline.Readline{}
mut line := ''
for {
line = ''
print('vlisp> ')
line = rl.read_line('') or { exit(1) }
mut expr := token(line)
expr << ' '
for expr[0] != ' ' {
expr_list := parse(mut expr) or { println(err) return }
result := eval(expr_list, mut env) or { println(err) return }
if result.str() != '' {
println(result)
}
}
if !(line.len > 0 && line != '') {
break
}
}
}
fn main() {
repl()
}
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels