compiler construction - Scheme interpreter in Go -
i'm quite basic go programmer , i've been taking @ small scheme interpreter , i've been trying understand how works.
i found here: https://pkelchte.wordpress.com/2013/12/31/scm-go/
i read webpage, i'm still struggling understand how works because source code written who's lot more familiar go am.
particularly there's these lines i'm struggling understand:
e := expression.(type) // line 73
i'm not sure .(type)
part means, thought casting doesn't casting i've seen before.
switch p := procedure.(type) { case func(...scmer) scmer: value = p(args...) case proc: en := &env{make(vars), p.en} switch params := p.params.(type) { case []scmer: i, param := range params { en.vars[param.(symbol)] = args[i] } default: en.vars[params.(symbol)] = args } value = eval(p.body, en)
i don't understand of code honest. lines 73 - 86
*tokens = (*tokens)[1:] // line 208
i'm not sure line means due it's weird syntax. pointers , parenthesises because of *. i'm not sure lines doing.
finally there's these lines:
token := (*tokens)[0] *tokens = (*tokens)[1:] switch token { case "(": //a list begins l := make([]scmer, 0) (*tokens)[0] != ")" { if := readfrom(tokens); != symbol("") { l = append(l, i) } } *tokens = (*tokens)[1:] return l
i don't know these lines either. lines 198 - 209
here's complete code if want it, realise it's 250 lines long i'd appreciate many explanations doing possible.
/* * minimal scheme interpreter, seen in lis.py , sicp * http://norvig.com/lispy.html * http://mitpress.mit.edu/sicp/full-text/sicp/book/node77.html * * pieter kelchtermans 2013 * license: wtfpl 2.0 */ package main import ( "bufio" "fmt" "log" "os" "reflect" "strconv" "strings" ) func main() { repl() } /* eval / apply */ func eval(expression scmer, en *env) (value scmer) { switch e := expression.(type) { case number: value = e case symbol: value = en.find(e).vars[e] case []scmer: switch car, _ := e[0].(symbol); car { case "quote": value = e[1] case "if": if eval(e[1], en).(bool) { value = eval(e[2], en) } else { value = eval(e[3], en) } case "set!": v := e[1].(symbol) en.find(v).vars[v] = eval(e[2], en) value = "ok" case "define": en.vars[e[1].(symbol)] = eval(e[2], en) value = "ok" case "lambda": value = proc{e[1], e[2], en} case "begin": _, := range e[1:] { value = eval(i, en) } default: operands := e[1:] values := make([]scmer, len(operands)) i, x := range operands { values[i] = eval(x, en) } value = apply(eval(e[0], en), values) } default: log.println("unknown expression type - eval", e) } return } func apply(procedure scmer, args []scmer) (value scmer) { switch p := procedure.(type) { case func(...scmer) scmer: value = p(args...) case proc: en := &env{make(vars), p.en} switch params := p.params.(type) { case []scmer: i, param := range params { en.vars[param.(symbol)] = args[i] } default: en.vars[params.(symbol)] = args } value = eval(p.body, en) default: log.println("unknown procedure type - apply", p) } return } type proc struct { params, body scmer en *env } /* environments */ type vars map[symbol]scmer type env struct { vars outer *env } func (e *env) find(s symbol) *env { if _, ok := e.vars[s]; ok { return e } else { return e.outer.find(s) } } /* primitives */ var globalenv env func init() { globalenv = env{ vars{ //aka incomplete set of compiled-in functions "+": func(a ...scmer) scmer { v := a[0].(number) _, := range a[1:] { v += i.(number) } return v }, "-": func(a ...scmer) scmer { v := a[0].(number) _, := range a[1:] { v -= i.(number) } return v }, "*": func(a ...scmer) scmer { v := a[0].(number) _, := range a[1:] { v *= i.(number) } return v }, "/": func(a ...scmer) scmer { v := a[0].(number) _, := range a[1:] { v /= i.(number) } return v }, "<=": func(a ...scmer) scmer { return a[0].(number) <= a[1].(number) }, "equal?": func(a ...scmer) scmer { return reflect.deepequal(a[0], a[1]) }, "cons": func(a ...scmer) scmer { switch car := a[0]; cdr := a[1].(type) { case []scmer: return append([]scmer{car}, cdr...) default: return []scmer{car, cdr} } }, "car": func(a ...scmer) scmer { return a[0].([]scmer)[0] }, "cdr": func(a ...scmer) scmer { return a[0].([]scmer)[1:] }, "list": eval(read( "(lambda z z)"), &globalenv), }, nil} } /* parsing */ //symbols, numbers, expressions, procedures, lists, ... implement interface, enables passing them along in interpreter type scmer interface{} type symbol string //symbols represented strings type number float64 //numbers float64 func read(s string) (expression scmer) { tokens := tokenize(s) return readfrom(&tokens) } //syntactic analysis func readfrom(tokens *[]string) (expression scmer) { //pop first element tokens token := (*tokens)[0] *tokens = (*tokens)[1:] switch token { case "(": //a list begins l := make([]scmer, 0) (*tokens)[0] != ")" { if := readfrom(tokens); != symbol("") { l = append(l, i) } } *tokens = (*tokens)[1:] return l default: //an atom occurs if f, err := strconv.parsefloat(token, 64); err == nil { return number(f) } else { return symbol(token) } } } //lexical analysis func tokenize(s string) []string { return strings.split( strings.replace(strings.replace(s, "(", "( ", -1), ")", " )", -1), " ") } /* interactivity */ func string(v scmer) string { switch v := v.(type) { case []scmer: l := make([]string, len(v)) i, x := range v { l[i] = string(x) } return "(" + strings.join(l, " ") + ")" default: return fmt.sprint(v) } } func repl() { scanner := bufio.newscanner(os.stdin) fmt.print("> "); scanner.scan(); fmt.print("> ") { fmt.println("==>", string(eval(read(scanner.text()), &globalenv))) } }
first 1 type switch. can read more here.
second 1 slicing in python (if know it, should familiar)
ls = ls[1:]
we're skipping first item , taking rest of slice/list.
as see comments, think it's not starting point experiment golang.
Comments
Post a Comment