├── .gitattributes ├── .gitignore ├── README.md ├── anony.go ├── base.go ├── builtin.go ├── chan.go ├── compare.go ├── compute.go ├── conv └── conv.go ├── decorate.go ├── error.go ├── example ├── README.md ├── console.go ├── default.go ├── list.lsp ├── macro.lsp ├── math.lsp ├── omission.go ├── sort.lsp └── yield.lsp ├── feed.go ├── flow.go ├── io.go ├── label.go ├── lisp.go ├── logic.go ├── math └── math.go ├── parser ├── example │ └── calc.go ├── parse.go └── type.go ├── pattern.go ├── section.go └── token.go /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | lisp 2 | 3 | ==== 4 | 5 | a simple lisp made by go 6 | 7 | 一个简单的go-lisp实现,基本遵循lisp标准语法,包含一些(可能)独有的函数或规则 8 | 9 | 支持输入四种基本类型:整数、浮点数、字符、字符串 10 | 11 | 内部支持三种基本类型:整数、浮点数、字符(字符作为整数保存) 12 | 13 | 支持四则运算、比较运算、逻辑运算(逻辑运算和cons是懒惰执行的) 14 | 15 | 以下是所有内置函数的简介: 16 | 17 | none 返回一个空值,如果出现错误,一定要返回空值 18 | 19 | eval 为将一个列表在当前作用域下执行 20 | 21 | quote 返回参数本身,主要用于保护一个列表 22 | 23 | atom 如果参数不是列表或者是空列表则返回真,否则返回假 24 | 25 | eq 判断两个元素是否相等(对内部注册函数和default或omission返回的函数会出错) 26 | 27 | car 返回列表的第一个元素 28 | 29 | cdr 返回除去第一个元素后的列表 30 | 31 | cons 返回将一个元素加入到列表的头部的列表 32 | 33 | each 为顺序执行多个语句,最后一个语句的返回值作为返回值 34 | 35 | block 类似 each 但会产生一个内层环境 36 | 37 | if 三个参数,根据第一个的结果决定执行第二个还是第三个(可以看成是cond的包装) 38 | 39 | cond 参数为一系列的二元列表,依次执行列表的第一个元素,直到返回为真时执行第二个元素并退出 40 | 41 | while 二个参数,循环执行第二个直到第一个判断为假 42 | 43 | until 二个参数,循环执行第二个直到第一个判断为真 44 | 45 | loop 三个参数,第一个初始化,循环执行第三个直到第二个判断为假 46 | 47 | for 三个参数,第一个必须是标签,第二个必须是生成器,循环执行第三个(生成器返回值赋给第一个) 48 | 49 | each、block 返回最后被执行的语句的值 50 | 51 | if cond 也一样(if如果第二选项省略,判断又为假,返回none) 52 | 53 | while、until、loop、for 如果被正确执行,永远返回none 54 | 55 | present 返回当前环境中的所有标签 56 | 57 | context 返回当前环境可以查找到的所有标签,亦即所有可用的标签 58 | 59 | builtin 内部注册函数无法被删除只能被内层环境覆盖,builtin直接查找内部注册函数 60 | 61 | remove 从当前环境中删除一个标签,如果不存在会向外查找,试图删除内部注册函数会导致错误 62 | 63 | clear 删除当前环境中的所有标签(不包括其父环境或更上层环境的标签) 64 | 65 | lambda 产生一个匿名函数 66 | 67 | macro 产生一个匿名宏,macro宏与define、update不同之处在于可以添加额外的替换对象 68 | 69 | define 声明一个标签为变量或者函数,标签建立在当前环境下 70 | 71 | (define f 1) 声明一个变量 72 | 73 | (define (f n) (* n 2)) 声明一个函数 74 | 75 | 如果要声明一个变量为宏,需使用macro才行 76 | 77 | update 用来更新一个标签的值,用法和lambda相同,但它只能更新已有的标签的值 78 | 79 | update 会顺序查找环境(注意闭包的生成时环境设定为嵌入在运行时环境和外部环境之间) 80 | 81 | update 如果查找不到,或者查找到的是内部注册函数,会报错 82 | 83 | pretreat 用于宏的参数预处理,第一个参数必须是宏,且后跟元素个数等于宏参数个数 84 | 85 | default 用于给函数或宏绑定默认值,返回一个绑定了默认值(因而可以省略后面参数)的函数 86 | 87 | omission 用于产生一个可变参数函数,提供的参数必须是一个函数,该函数的最后一个参数应该为列表 88 | 89 | scan 从控制台获取字符串数据,并将该数据作为lisp语句执行后返回 90 | 91 | load 读取一个lisp文件,并执行其内容后返回 92 | 93 | print 输出数据 94 | 95 | println 输出数据并回车 96 | 97 | raise 将字符串转化为错误并释放 98 | 99 | error 打印可能的错误,并向外传递错误 100 | 101 | catch 捕获错误并转化为字符串,否则返回一个空表 102 | 103 | chan 生成一个channel 104 | 105 | close 关闭一个channel 106 | 107 | go 在一个新的线程里执行语句 108 | 109 | channel可以像函数一样执行,如不提供参数为读取,可接受一个参数来写入 110 | 111 | 可以通过Add方法添加自定义函数: 112 | 113 | func (l *Lisp)Add(name string, func([]Token,*Lisp)(Token,error)) 114 | 115 | 事实上,func([]Token,*Lisp)(Token,error)被定义为lisp.Gfac类型,是注册函数的类型 116 | 117 | 使用者需要自行检验参数的数量,对每个参数进行Exec运算获取实际参数,验证参数类型 118 | 119 | Token为内部用来表示元素的类型 120 | 121 | type Token struct{ 122 | Kind 123 | Text interface{} 124 | } 125 | 126 | Text只可能装入如下类型:[]Token、int64、float64、string、Name、Hong、Lfac、Gfac 127 | 128 | 对应的Kind值分别为如下:List、Int、Float、String、Macro、Label、Front、Back 129 | 130 | 交互模式和lsp文件中都支持注释,只有一种注释形式:‘#’及该行剩余部分被忽略 131 | 132 | 注意的是为了实现惰性求值,你添加的函数接收到的切片,每个元素都是未运算的,需要你进行运算或解包 133 | 134 | 为了帮助lambda实现递归调用,内置标识符 self 代表本函数,命名函数也应尽量使用 self 来递归 135 | 136 | 命名函数使用函数名递归是可行的,但如果你将函数赋给一个值,并将原函数名另外赋值的话,会导致异常 137 | 138 | self 可以避免这种异常,因此应尽量使用 self 标识符进行递归 139 | 140 | 具体使用参见example 141 | -------------------------------------------------------------------------------- /anony.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | func init() { 4 | Add("macro", func(t []Token, p *Lisp) (ans Token, err error) { 5 | var ( 6 | a, b, c Token 7 | x, y []Name 8 | ) 9 | switch len(t) { 10 | case 2: 11 | a, b = t[0], t[1] 12 | case 3: 13 | a, c, b = t[0], t[1], t[2] 14 | if c.Kind != List { 15 | return None, ErrFitType 16 | } 17 | t = c.Text.([]Token) 18 | y = make([]Name, len(t)) 19 | for i, u := range t { 20 | if u.Kind != Label { 21 | return None, ErrNotName 22 | } 23 | y[i] = u.Text.(Name) 24 | } 25 | default: 26 | return None, ErrParaNum 27 | } 28 | if a.Kind != List || b.Kind != List { 29 | return None, ErrFitType 30 | } 31 | t = a.Text.([]Token) 32 | x = make([]Name, len(t)) 33 | for i, u := range t { 34 | if u.Kind != Label { 35 | return None, ErrNotName 36 | } 37 | x[i] = u.Text.(Name) 38 | } 39 | ans = Token{Macro, &Hong{x, b.Text.([]Token), y}} 40 | return ans, nil 41 | }) 42 | Add("lambda", func(t []Token, p *Lisp) (ans Token, err error) { 43 | if len(t) != 2 { 44 | return None, ErrParaNum 45 | } 46 | a, b := t[0], t[1] 47 | if a.Kind != List { 48 | return None, ErrFitType 49 | } 50 | if b.Kind != List { 51 | return None, ErrFitType 52 | } 53 | t = a.Text.([]Token) 54 | x := make([]Name, 0, len(t)) 55 | for _, i := range t { 56 | if i.Kind != Label { 57 | return None, ErrNotName 58 | } 59 | x = append(x, i.Text.(Name)) 60 | } 61 | ans = Token{Front, &Lfac{x, b.Text.([]Token), p}} 62 | return ans, nil 63 | }) 64 | } 65 | -------------------------------------------------------------------------------- /base.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/hydra13142/lisp/parser" 7 | ) 8 | 9 | type Kind int 10 | 11 | type Name string 12 | 13 | type Gfac func([]Token, *Lisp) (Token, error) 14 | 15 | type Hong struct { 16 | Para []Name 17 | Text []Token 18 | Real []Name 19 | } 20 | 21 | type Lfac struct { 22 | Para []Name 23 | Text []Token 24 | Make *Lisp 25 | } 26 | 27 | const ( 28 | Null Kind = iota 29 | Int 30 | Float 31 | String 32 | Chan 33 | Fold 34 | List 35 | Back 36 | Macro 37 | Front 38 | Label 39 | Operator 40 | ) 41 | 42 | var ( 43 | pattern = &parser.Pattern{} 44 | 45 | True = Token{Int, int64(1)} 46 | False = Token{List, []Token(nil)} 47 | None = Token{} 48 | 49 | Global = &Lisp{env: map[Name]Token{}, dad: nil} 50 | 51 | ErrNotOver = errors.New("Cannot scan to the end") 52 | ErrUnquote = errors.New("Quote is unfold") 53 | ErrNotFind = errors.New("Not find this Name") 54 | ErrNotFunc = errors.New("Not a function") 55 | ErrParaNum = errors.New("Wrong parament number") 56 | ErrFitType = errors.New("Lisp type is wrong") 57 | ErrNotName = errors.New("This's not a Name") 58 | ErrIsEmpty = errors.New("Fold is empty") 59 | ErrNotConv = errors.New("Cannot translate") 60 | ErrRefused = errors.New("Can't remove a back function") 61 | ErrIsClose = errors.New("Channel has been closed") 62 | ) 63 | 64 | func (t Kind) String() string { 65 | switch t { 66 | case Int: 67 | return "int" 68 | case Float: 69 | return "float" 70 | case String: 71 | return "string" 72 | case Chan: 73 | return "channel" 74 | case Fold: 75 | return "fold list" 76 | case List: 77 | return "list" 78 | case Back: 79 | return "go" 80 | case Macro: 81 | return "macro" 82 | case Front: 83 | return "lisp" 84 | case Label: 85 | return "Name" 86 | case Operator: 87 | return "operator" 88 | } 89 | return "unknown" 90 | } 91 | 92 | func (m Hong) String() string { 93 | return fmt.Sprintf("{macro : %v | %v => %v}", m.Para, m.Real, m.Text) 94 | } 95 | 96 | func (l Lfac) String() string { 97 | return fmt.Sprintf("{front : %v => %v}", l.Para, l.Text) 98 | } 99 | -------------------------------------------------------------------------------- /builtin.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | func init() { 4 | Add("none", func(t []Token, p *Lisp) (Token, error) { 5 | if len(t) != 0 { 6 | return None, ErrParaNum 7 | } 8 | return None, nil 9 | }) 10 | Add("atom", func(t []Token, p *Lisp) (Token, error) { 11 | if len(t) != 1 { 12 | return None, ErrParaNum 13 | } 14 | x, err := p.Exec(t[0]) 15 | if err != nil { 16 | return None, err 17 | } 18 | if x.Kind != List || len(x.Text.([]Token)) == 0 { 19 | return True, nil 20 | } else { 21 | return False, nil 22 | } 23 | }) 24 | Add("eq", func(t []Token, p *Lisp) (Token, error) { 25 | if len(t) != 2 { 26 | return None, ErrParaNum 27 | } 28 | x, err := p.Exec(t[0]) 29 | if err != nil { 30 | return None, err 31 | } 32 | y, err := p.Exec(t[1]) 33 | if err != nil { 34 | return None, err 35 | } 36 | if x.Kind == Back || y.Kind == Back { 37 | return None, ErrFitType 38 | } 39 | if x.Eq(&y) { 40 | return True, nil 41 | } else { 42 | return False, nil 43 | } 44 | }) 45 | Add("car", func(t []Token, p *Lisp) (Token, error) { 46 | if len(t) != 1 { 47 | return None, ErrParaNum 48 | } 49 | x, err := p.Exec(t[0]) 50 | if err != nil { 51 | return None, err 52 | } 53 | if x.Kind == List { 54 | if len(x.Text.([]Token)) != 0 { 55 | return x.Text.([]Token)[0], nil 56 | } 57 | return None, ErrIsEmpty 58 | } 59 | return None, ErrFitType 60 | }) 61 | Add("cdr", func(t []Token, p *Lisp) (Token, error) { 62 | if len(t) != 1 { 63 | return None, ErrParaNum 64 | } 65 | x, err := p.Exec(t[0]) 66 | if err != nil { 67 | return None, err 68 | } 69 | if x.Kind == List { 70 | if len(x.Text.([]Token)) != 0 { 71 | return Token{List, x.Text.([]Token)[1:]}, nil 72 | } 73 | return None, ErrIsEmpty 74 | } 75 | return None, ErrFitType 76 | }) 77 | Add("cons", func(t []Token, p *Lisp) (Token, error) { 78 | if len(t) != 2 { 79 | return None, ErrParaNum 80 | } 81 | x, err := p.Exec(t[0]) 82 | if err != nil { 83 | return None, err 84 | } 85 | y, err := p.Exec(t[1]) 86 | if err != nil { 87 | return None, err 88 | } 89 | if y.Kind == List { 90 | a := y.Text.([]Token) 91 | b := make([]Token, len(a)+1) 92 | b[0] = x 93 | copy(b[1:], a) 94 | return Token{List, b}, nil 95 | } 96 | return None, ErrFitType 97 | }) 98 | Add("eval", func(t []Token, p *Lisp) (Token, error) { 99 | if len(t) != 1 { 100 | return None, ErrParaNum 101 | } 102 | ans, err := p.Exec(t[0]) 103 | if err != nil { 104 | return None, err 105 | } 106 | return p.Exec(ans) 107 | }) 108 | Add("quote", func(t []Token, p *Lisp) (Token, error) { 109 | if len(t) != 1 { 110 | return None, ErrParaNum 111 | } 112 | if t[0].Kind == Label { 113 | return p.Exec(t[0]) 114 | } 115 | return t[0], nil 116 | }) 117 | } 118 | -------------------------------------------------------------------------------- /chan.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | func init() { 4 | Add("chan", func(t []Token, p *Lisp) (ans Token, err error) { 5 | switch len(t) { 6 | case 0: 7 | return Token{Chan, make(chan Token)}, nil 8 | case 1: 9 | u, err := p.Exec(t[0]) 10 | if err != nil { 11 | return None, err 12 | } 13 | if u.Kind != Int { 14 | return None, ErrFitType 15 | } 16 | return Token{Chan, make(chan Token, int(u.Text.(int64)))}, nil 17 | } 18 | return None, ErrParaNum 19 | }) 20 | Add("close", func(t []Token, p *Lisp) (ans Token, err error) { 21 | if len(t) != 1 { 22 | return None, ErrParaNum 23 | } 24 | u, err := p.Exec(t[0]) 25 | if err != nil { 26 | return None, err 27 | } 28 | if u.Kind != Chan { 29 | return None, ErrFitType 30 | } 31 | close(u.Text.(chan Token)) 32 | return None, nil 33 | }) 34 | Add("go", func(t []Token, p *Lisp) (ans Token, err error) { 35 | if len(t) != 1 { 36 | return None, ErrParaNum 37 | } 38 | go p.Exec(t[0]) 39 | return None, nil 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /compare.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | func init() { 4 | Add(">", func(t []Token, p *Lisp) (Token, error) { 5 | if len(t) != 2 { 6 | return None, ErrParaNum 7 | } 8 | x, err := p.Exec(t[0]) 9 | if err != nil { 10 | return None, err 11 | } 12 | y, err := p.Exec(t[1]) 13 | if err != nil { 14 | return None, err 15 | } 16 | switch x.Kind { 17 | case Fold, Back, Front: 18 | return None, ErrFitType 19 | default: 20 | switch y.Kind { 21 | case List, Back, Front: 22 | return None, ErrFitType 23 | default: 24 | if z := x.Cmp(&y); z > 0 { 25 | return True, nil 26 | } else { 27 | return False, nil 28 | } 29 | } 30 | } 31 | }) 32 | Add(">=", func(t []Token, p *Lisp) (Token, error) { 33 | if len(t) != 2 { 34 | return None, ErrParaNum 35 | } 36 | x, err := p.Exec(t[0]) 37 | if err != nil { 38 | return None, err 39 | } 40 | y, err := p.Exec(t[1]) 41 | if err != nil { 42 | return None, err 43 | } 44 | switch x.Kind { 45 | case Fold, Back, Front: 46 | return None, ErrFitType 47 | default: 48 | switch y.Kind { 49 | case Fold, Back, Front: 50 | return None, ErrFitType 51 | default: 52 | if z := x.Cmp(&y); z >= 0 { 53 | return True, nil 54 | } else { 55 | return False, nil 56 | } 57 | } 58 | } 59 | }) 60 | Add("<", func(t []Token, p *Lisp) (Token, error) { 61 | if len(t) != 2 { 62 | return None, ErrParaNum 63 | } 64 | x, err := p.Exec(t[0]) 65 | if err != nil { 66 | return None, err 67 | } 68 | y, err := p.Exec(t[1]) 69 | if err != nil { 70 | return None, err 71 | } 72 | switch x.Kind { 73 | case Fold, Back, Front: 74 | return None, ErrFitType 75 | default: 76 | switch y.Kind { 77 | case Fold, Back, Front: 78 | return None, ErrFitType 79 | default: 80 | if z := x.Cmp(&y); z < 0 { 81 | return True, nil 82 | } else { 83 | return False, nil 84 | } 85 | } 86 | } 87 | }) 88 | Add("<=", func(t []Token, p *Lisp) (Token, error) { 89 | if len(t) != 2 { 90 | return None, ErrParaNum 91 | } 92 | x, err := p.Exec(t[0]) 93 | if err != nil { 94 | return None, err 95 | } 96 | y, err := p.Exec(t[1]) 97 | if err != nil { 98 | return None, err 99 | } 100 | switch x.Kind { 101 | case Fold, Back, Front: 102 | return None, ErrFitType 103 | default: 104 | switch y.Kind { 105 | case Fold, Back, Front: 106 | return None, ErrFitType 107 | default: 108 | if z := x.Cmp(&y); z <= 0 { 109 | return True, nil 110 | } else { 111 | return False, nil 112 | } 113 | } 114 | } 115 | }) 116 | Add("==", func(t []Token, p *Lisp) (Token, error) { 117 | if len(t) != 2 { 118 | return None, ErrParaNum 119 | } 120 | x, err := p.Exec(t[0]) 121 | if err != nil { 122 | return None, err 123 | } 124 | y, err := p.Exec(t[1]) 125 | if err != nil { 126 | return None, err 127 | } 128 | switch x.Kind { 129 | case Fold, Back, Front: 130 | return None, ErrFitType 131 | default: 132 | switch y.Kind { 133 | case Fold, Back, Front: 134 | return None, ErrFitType 135 | default: 136 | if z := x.Cmp(&y); z == 0 { 137 | return True, nil 138 | } else { 139 | return False, nil 140 | } 141 | } 142 | } 143 | }) 144 | Add("!=", func(t []Token, p *Lisp) (Token, error) { 145 | if len(t) != 2 { 146 | return None, ErrParaNum 147 | } 148 | x, err := p.Exec(t[0]) 149 | if err != nil { 150 | return None, err 151 | } 152 | y, err := p.Exec(t[1]) 153 | if err != nil { 154 | return None, err 155 | } 156 | switch x.Kind { 157 | case Fold, Back, Front: 158 | return None, ErrFitType 159 | default: 160 | switch y.Kind { 161 | case Fold, Back, Front: 162 | return None, ErrFitType 163 | default: 164 | if z := x.Cmp(&y); z != 0 { 165 | return True, nil 166 | } else { 167 | return False, nil 168 | } 169 | } 170 | } 171 | }) 172 | } 173 | -------------------------------------------------------------------------------- /compute.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | func init() { 4 | Add("+", func(t []Token, p *Lisp) (Token, error) { 5 | if len(t) != 2 { 6 | return None, ErrParaNum 7 | } 8 | x, err := p.Exec(t[0]) 9 | if err != nil { 10 | return None, err 11 | } 12 | y, err := p.Exec(t[1]) 13 | if err != nil { 14 | return None, err 15 | } 16 | switch x.Kind { 17 | case Int: 18 | switch y.Kind { 19 | case Int: 20 | return Token{Int, x.Text.(int64) + y.Text.(int64)}, nil 21 | case Float: 22 | return Token{Float, float64(x.Text.(int64)) + y.Text.(float64)}, nil 23 | } 24 | case Float: 25 | switch y.Kind { 26 | case Int: 27 | return Token{Float, x.Text.(float64) + float64(y.Text.(int64))}, nil 28 | case Float: 29 | return Token{Float, x.Text.(float64) + y.Text.(float64)}, nil 30 | } 31 | case String: 32 | switch y.Kind { 33 | case String: 34 | return Token{String, x.Text.(string) + y.Text.(string)}, nil 35 | } 36 | case List: 37 | switch y.Kind { 38 | case List: 39 | a, b := x.Text.([]Token), y.Text.([]Token) 40 | c := make([]Token, len(a)+len(b)) 41 | copy(c, a) 42 | copy(c[len(a):], b) 43 | return Token{List, c}, nil 44 | } 45 | 46 | } 47 | return None, ErrFitType 48 | }) 49 | Add("-", func(t []Token, p *Lisp) (Token, error) { 50 | if len(t) != 2 { 51 | return None, ErrParaNum 52 | } 53 | x, err := p.Exec(t[0]) 54 | if err != nil { 55 | return None, err 56 | } 57 | y, err := p.Exec(t[1]) 58 | if err != nil { 59 | return None, err 60 | } 61 | switch x.Kind { 62 | case Int: 63 | switch y.Kind { 64 | case Int: 65 | return Token{Int, x.Text.(int64) - y.Text.(int64)}, nil 66 | case Float: 67 | return Token{Float, float64(x.Text.(int64)) - y.Text.(float64)}, nil 68 | } 69 | case Float: 70 | switch y.Kind { 71 | case Int: 72 | return Token{Float, x.Text.(float64) - float64(y.Text.(int64))}, nil 73 | case Float: 74 | return Token{Float, x.Text.(float64) - y.Text.(float64)}, nil 75 | } 76 | } 77 | return None, ErrFitType 78 | }) 79 | Add("*", func(t []Token, p *Lisp) (Token, error) { 80 | if len(t) != 2 { 81 | return None, ErrParaNum 82 | } 83 | x, err := p.Exec(t[0]) 84 | if err != nil { 85 | return None, err 86 | } 87 | y, err := p.Exec(t[1]) 88 | if err != nil { 89 | return None, err 90 | } 91 | switch x.Kind { 92 | case Int: 93 | switch y.Kind { 94 | case Int: 95 | return Token{Int, x.Text.(int64) * y.Text.(int64)}, nil 96 | case Float: 97 | return Token{Float, float64(x.Text.(int64)) * y.Text.(float64)}, nil 98 | } 99 | case Float: 100 | switch y.Kind { 101 | case Int: 102 | return Token{Float, x.Text.(float64) * float64(y.Text.(int64))}, nil 103 | case Float: 104 | return Token{Float, x.Text.(float64) * y.Text.(float64)}, nil 105 | } 106 | } 107 | return None, ErrFitType 108 | }) 109 | Add("/", func(t []Token, p *Lisp) (Token, error) { 110 | if len(t) != 2 { 111 | return None, ErrParaNum 112 | } 113 | x, err := p.Exec(t[0]) 114 | if err != nil { 115 | return None, err 116 | } 117 | y, err := p.Exec(t[1]) 118 | if err != nil { 119 | return None, err 120 | } 121 | switch x.Kind { 122 | case Int: 123 | switch y.Kind { 124 | case Int: 125 | return Token{Int, x.Text.(int64) / y.Text.(int64)}, nil 126 | case Float: 127 | return Token{Float, float64(x.Text.(int64)) / y.Text.(float64)}, nil 128 | } 129 | case Float: 130 | switch y.Kind { 131 | case Int: 132 | return Token{Float, x.Text.(float64) / float64(y.Text.(int64))}, nil 133 | case Float: 134 | return Token{Float, x.Text.(float64) / y.Text.(float64)}, nil 135 | } 136 | } 137 | return None, ErrFitType 138 | }) 139 | Add("%", func(t []Token, p *Lisp) (Token, error) { 140 | if len(t) != 2 { 141 | return None, ErrParaNum 142 | } 143 | x, err := p.Exec(t[0]) 144 | if err != nil { 145 | return None, err 146 | } 147 | y, err := p.Exec(t[1]) 148 | if err != nil { 149 | return None, err 150 | } 151 | if x.Kind == Int && y.Kind == Int { 152 | return Token{Int, x.Text.(int64) % y.Text.(int64)}, nil 153 | } 154 | return None, ErrFitType 155 | }) 156 | } 157 | -------------------------------------------------------------------------------- /conv/conv.go: -------------------------------------------------------------------------------- 1 | package conv 2 | 3 | import ( 4 | "github.com/hydra13142/lisp" 5 | "github.com/hydra13142/parser" 6 | ) 7 | 8 | func Int(t []lisp.Token, p *lisp.Lisp) (lisp.Token, error) { 9 | if len(t) != 1 { 10 | return lisp.None, lisp.ErrParaNum 11 | } 12 | u, err := p.Exec(t[0]) 13 | if err != nil { 14 | return lisp.None, err 15 | } 16 | switch u.Kind { 17 | case lisp.Int: 18 | return u, nil 19 | case lisp.Float: 20 | return lisp.Token{lisp.Int, int64(u.Text.(float64))}, nil 21 | case lisp.String: 22 | a, b := parser.ParseInt([]byte(u.Text.(string))) 23 | if b == 0 { 24 | return lisp.None, lisp.ErrNotConv 25 | } 26 | return lisp.Token{lisp.Int, a}, nil 27 | } 28 | return lisp.None, lisp.ErrFitType 29 | } 30 | 31 | func Float(t []lisp.Token, p *lisp.Lisp) (lisp.Token, error) { 32 | if len(t) != 1 { 33 | return lisp.None, lisp.ErrParaNum 34 | } 35 | u, err := p.Exec(t[0]) 36 | if err != nil { 37 | return lisp.None, err 38 | } 39 | switch u.Kind { 40 | case lisp.Int: 41 | return lisp.Token{lisp.Float, float64(u.Text.(int64))}, nil 42 | case lisp.Float: 43 | return u, nil 44 | case lisp.String: 45 | a, b := parser.ParseFloat([]byte(u.Text.(string))) 46 | if b == 0 { 47 | return lisp.None, lisp.ErrNotConv 48 | } 49 | return lisp.Token{lisp.Float, a}, nil 50 | } 51 | return lisp.None, lisp.ErrFitType 52 | } 53 | 54 | 55 | func List(t []lisp.Token, p *lisp.Lisp) (lisp.Token, error) { 56 | if len(t) != 1 { 57 | return lisp.None, lisp.ErrParaNum 58 | } 59 | u, err := p.Exec(t[0]) 60 | if err != nil { 61 | return lisp.None, err 62 | } 63 | if u.Kind != lisp.String { 64 | return lisp.None, lisp.ErrFitType 65 | } 66 | s := u.Text.(string) 67 | x := make([]lisp.Token, 0, len(s)) 68 | for _, c := range s { 69 | x = append(x, lisp.Token{lisp.Int, int64(c)}) 70 | } 71 | return lisp.Token{lisp.List, x}, nil 72 | } 73 | 74 | func String(t []lisp.Token, p *lisp.Lisp) (lisp.Token, error) { 75 | if len(t) != 1 { 76 | return lisp.None, lisp.ErrParaNum 77 | } 78 | u, err := p.Exec(t[0]) 79 | if err != nil { 80 | return lisp.None, err 81 | } 82 | if u.Kind != lisp.List { 83 | return lisp.None, lisp.ErrFitType 84 | } 85 | s := u.Text.([]lisp.Token) 86 | x := make([]rune, 0, len(s)) 87 | for _, c := range s { 88 | if c.Kind != lisp.Int { 89 | return lisp.None, lisp.ErrFitType 90 | } 91 | x = append(x, rune(c.Text.(int64))) 92 | } 93 | return lisp.Token{lisp.String, string(x)}, nil 94 | } 95 | -------------------------------------------------------------------------------- /decorate.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | func init() { 4 | Add("pretreat", func(t []Token, p *Lisp) (Token, error) { 5 | var ( 6 | x, y Token 7 | err error 8 | ) 9 | x, err = p.Exec(t[0]) 10 | if err != nil { 11 | return None, err 12 | } 13 | if x.Kind == Macro { 14 | f := x.Text.(*Hong) 15 | n := f.Para 16 | if len(n) != len(t)-1 { 17 | return None, ErrParaNum 18 | } 19 | hold := make([]bool, len(n)) 20 | for i, z := range t[1:] { 21 | y, err = p.Exec(z) 22 | if err != nil { 23 | return None, err 24 | } 25 | hold[i] = y.Bool() 26 | } 27 | return Token{Back, Gfac(func(t2 []Token, p2 *Lisp) (Token, error) { 28 | if len(t2) != len(n) { 29 | return None, ErrParaNum 30 | } 31 | m := make([]Token, len(n)+1) 32 | m[0] = x 33 | for i, t := range hold { 34 | if t { 35 | u, err := p.Exec(t2[i]) 36 | if err != nil { 37 | return None, err 38 | } 39 | m[i+1] = u 40 | } else { 41 | m[i+1] = t2[i] 42 | } 43 | } 44 | return p2.Exec(Token{List, m}) 45 | })}, nil 46 | } 47 | return None, ErrFitType 48 | }) 49 | Add("default", func(t []Token, p *Lisp) (Token, error) { 50 | var ( 51 | x, y Token 52 | err error 53 | ) 54 | x, err = p.Exec(t[0]) 55 | if err != nil { 56 | return None, err 57 | } 58 | switch x.Kind { 59 | case Macro: 60 | g := x.Text.(*Hong) 61 | n := g.Para 62 | if len(n) < len(t)-1 { 63 | return None, ErrParaNum 64 | } 65 | hold := t[1:] 66 | return Token{Back, Gfac(func(t2 []Token, p2 *Lisp) (Token, error) { 67 | if len(t2) > len(n) || len(t2)+len(hold) < len(n) { 68 | return None, ErrParaNum 69 | } 70 | m := make([]Token, len(n)+1) 71 | m[0] = x 72 | copy(m[1:], t2) 73 | copy(m[len(t2)+1:], hold[len(t2)+len(hold)-len(n):]) 74 | return p2.Exec(Token{List, m}) 75 | })}, nil 76 | case Front: 77 | f := x.Text.(*Lfac) 78 | n := f.Para 79 | if len(n) < len(t)-1 { 80 | return None, ErrParaNum 81 | } 82 | hold := make([]Token, len(t)-1) 83 | for i, z := range t[1:] { 84 | y, err = p.Exec(z) 85 | if err != nil { 86 | return None, err 87 | } 88 | hold[i] = y 89 | } 90 | return Token{Back, Gfac(func(t2 []Token, p2 *Lisp) (Token, error) { 91 | if len(t2) > len(n) || len(t2)+len(hold) < len(n) { 92 | return None, ErrParaNum 93 | } 94 | q := &Lisp{dad: f.Make, env: map[Name]Token{}} 95 | for i, z := range t2 { 96 | y, err = p.Exec(z) 97 | if err != nil { 98 | return None, err 99 | } 100 | q.env[n[i]] = y 101 | } 102 | for i, j := len(n)-1, 1; i >= len(t2); i, j = i-1, j+1 { 103 | q.env[n[i]] = hold[len(hold)-j] 104 | } 105 | return q.Exec(Token{List, f.Text}) 106 | })}, nil 107 | } 108 | return None, ErrFitType 109 | }) 110 | Add("omission", func(t []Token, p *Lisp) (Token, error) { 111 | var ( 112 | x, y Token 113 | err error 114 | ) 115 | if len(t) != 1 { 116 | return None, ErrParaNum 117 | } 118 | x, err = p.Exec(t[0]) 119 | if err != nil { 120 | return None, err 121 | } 122 | if x.Kind == Front { 123 | f := x.Text.(*Lfac) 124 | n := f.Para 125 | return Token{Back, Gfac(func(t2 []Token, p2 *Lisp) (Token, error) { 126 | if len(t2) < len(n)-1 { 127 | return None, ErrParaNum 128 | } 129 | q := &Lisp{dad: f.Make, env: map[Name]Token{}} 130 | for i := len(n) - 2; i >= 0; i-- { 131 | y, err = p.Exec(t2[i]) 132 | if err != nil { 133 | return None, err 134 | } 135 | q.env[n[i]] = y 136 | } 137 | z := make([]Token, 0, len(t2)-len(n)+1) 138 | for i := len(n) - 1; i < len(t2); i++ { 139 | y, err = p.Exec(t2[i]) 140 | if err != nil { 141 | return None, err 142 | } 143 | z = append(z, y) 144 | } 145 | q.env[n[len(n)-1]] = Token{List, z} 146 | return q.Exec(Token{List, f.Text}) 147 | })}, nil 148 | } 149 | return None, ErrFitType 150 | }) 151 | } 152 | -------------------------------------------------------------------------------- /error.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | import "fmt" 4 | 5 | func init() { 6 | Add("raise", func(t []Token, p *Lisp) (Token, error) { 7 | if len(t) != 1 { 8 | return None, ErrParaNum 9 | } 10 | ans, err := p.Exec(t[0]) 11 | if err != nil { 12 | return None, err 13 | } 14 | if ans.Kind != String { 15 | return None, ErrFitType 16 | } 17 | return None, fmt.Errorf(ans.Text.(string)) 18 | }) 19 | Add("catch", func(t []Token, p *Lisp) (Token, error) { 20 | if len(t) != 1 { 21 | return None, ErrParaNum 22 | } 23 | _, err := p.Exec(t[0]) 24 | if err != nil { 25 | return Token{String, fmt.Sprint(err)}, nil 26 | } 27 | return None, nil 28 | }) 29 | Add("error", func(t []Token, p *Lisp) (Token, error) { 30 | if len(t) != 1 { 31 | return None, ErrParaNum 32 | } 33 | ans, err := p.Exec(t[0]) 34 | if err != nil { 35 | fmt.Println(err) 36 | return None, err 37 | } 38 | return ans, nil 39 | }) 40 | } 41 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | example 2 | 3 | ==== 4 | 5 | 注意,执行时,请根据你安装库的位置修改import! 6 | 7 | 内部有几个lsp文件,可以用来测试,lsp文件中和交互模式都是可以有注释的,但是lisp.Lisp.Eval方法不能有注释 -------------------------------------------------------------------------------- /example/console.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hydra13142/lisp" 5 | "github.com/hydra13142/lisp/conv" 6 | "github.com/hydra13142/lisp/math" 7 | "os" 8 | ) 9 | 10 | var env *lisp.Lisp 11 | 12 | func main() { 13 | l := len(os.Args) - 1 14 | if l > 0 { 15 | for _, f := range os.Args[1:l] { 16 | env.Eval([]byte(`(load "` + f + `")`)) 17 | } 18 | if os.Args[l] != "-" { 19 | env.Eval([]byte(`(println (load "` + os.Args[l] + `"))`)) 20 | return 21 | } 22 | } 23 | env.Eval([]byte(` 24 | (loop 25 | () 26 | 1 27 | (each 28 | (println "==>") 29 | (catch 30 | (error 31 | (println (scan)) 32 | ) 33 | ) 34 | ) 35 | )`)) 36 | } 37 | func init() { 38 | 39 | lisp.Add("int", conv.Int) 40 | lisp.Add("float", conv.Float) 41 | lisp.Add("list", conv.List) 42 | lisp.Add("string", conv.String) 43 | 44 | lisp.Add("sin", math.Sin) 45 | lisp.Add("sinh", math.Sinh) 46 | lisp.Add("asin", math.Asin) 47 | lisp.Add("asinh", math.Asinh) 48 | lisp.Add("cos", math.Cos) 49 | lisp.Add("cosh", math.Cosh) 50 | lisp.Add("acos", math.Acos) 51 | lisp.Add("acosh", math.Acosh) 52 | lisp.Add("tan", math.Tan) 53 | lisp.Add("tanh", math.Tanh) 54 | lisp.Add("atan", math.Atan) 55 | lisp.Add("atanh", math.Atanh) 56 | lisp.Add("exp", math.Exp) 57 | lisp.Add("log", math.Log) 58 | lisp.Add("pow", math.Pow) 59 | lisp.Add("sqrt", math.Sqrt) 60 | 61 | env = lisp.NewLisp() 62 | } 63 | -------------------------------------------------------------------------------- /example/default.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/hydra13142/lisp" 4 | 5 | func main() { 6 | console := lisp.NewLisp() 7 | console.Eval([]byte(` 8 | (each 9 | (define 10 | (f x y z) 11 | (+ (+ x y) z) 12 | ) 13 | (define 14 | F 15 | (default f 1 2 3) 16 | ) 17 | (println 18 | (F) 19 | ) 20 | (println 21 | (F 3) 22 | ) 23 | (println 24 | (F 3 2) 25 | ) 26 | (println 27 | (F 3 2 1) 28 | ) 29 | ) 30 | `)) 31 | } 32 | -------------------------------------------------------------------------------- /example/list.lsp: -------------------------------------------------------------------------------- 1 | (define 2 | list 3 | (omission 4 | (lambda 5 | (l) 6 | (quote l) 7 | ) 8 | ) 9 | ) 10 | (define 11 | (range i j) 12 | (each 13 | (loop 14 | (define l ()) 15 | (< i j) 16 | (each 17 | (define j (- j 1)) 18 | (define l (cons j l)) 19 | ) 20 | ) 21 | l 22 | ) 23 | ) 24 | (define 25 | (len l) 26 | (if 27 | (atom l) 28 | 0 29 | (each 30 | (loop 31 | (define i 0) 32 | (not (atom l)) 33 | (each 34 | (define l (cdr l)) 35 | (define i (+ i 1)) 36 | ) 37 | ) 38 | i 39 | ) 40 | ) 41 | ) 42 | (define 43 | (index l i) 44 | (if 45 | (catch 46 | (each 47 | (loop 48 | () 49 | (!= i 0) 50 | (each 51 | (define i (- i 1)) 52 | (define l (cdr l)) 53 | ) 54 | ) 55 | (define c (car l)) 56 | ) 57 | ) 58 | (raise "out of range") 59 | c 60 | ) 61 | ) 62 | (define 63 | (reverse l) 64 | (each 65 | (loop 66 | (define s ()) 67 | (not (atom l)) 68 | (each 69 | (define i (car l)) 70 | (define l (cdr l)) 71 | (define s (cons i s)) 72 | ) 73 | ) 74 | s 75 | ) 76 | ) 77 | (define 78 | (slice l a b) 79 | (if 80 | (>= a b) 81 | () 82 | (if 83 | (> a 0) 84 | (self 85 | (cdr l) 86 | (- a 1) 87 | (- b 1) 88 | ) 89 | (cons 90 | (car l) 91 | (self 92 | (cdr l) 93 | 0 94 | (- b 1) 95 | ) 96 | ) 97 | ) 98 | ) 99 | ) 100 | (define 101 | (merge a b) 102 | (each 103 | (define 104 | (cmb a b c) 105 | (cond 106 | ((atom a) 107 | (+ (reverse c) b) 108 | ) 109 | ((atom b) 110 | (+ (reverse c) a) 111 | ) 112 | (1 113 | (each 114 | (define x (car a)) 115 | (define y (car b)) 116 | (if 117 | (< x y) 118 | (self 119 | (cdr a) 120 | b 121 | (cons x c) 122 | ) 123 | (self 124 | a 125 | (cdr b) 126 | (cons y c) 127 | ) 128 | ) 129 | ) 130 | ) 131 | ) 132 | ) 133 | (cmb a b ()) 134 | ) 135 | ) 136 | (define 137 | (map l f) 138 | (each 139 | (define s ()) 140 | (loop 141 | () 142 | (not (atom l)) 143 | (each 144 | (define i (car l)) 145 | (define l (cdr l)) 146 | (define s (cons (f i) s)) 147 | ) 148 | ) 149 | (reverse s) 150 | ) 151 | ) 152 | (define 153 | (filter l f) 154 | (each 155 | (define s ()) 156 | (loop 157 | () 158 | (not (atom l)) 159 | (each 160 | (define i (car l)) 161 | (define l (cdr l)) 162 | (if 163 | (f i) 164 | (define s (cons i s)) 165 | () 166 | ) 167 | ) 168 | ) 169 | (reverse s) 170 | ) 171 | ) 172 | (quote "ok") -------------------------------------------------------------------------------- /example/macro.lsp: -------------------------------------------------------------------------------- 1 | (define 2 | += 3 | (macro 4 | (a b) 5 | (define a (+ a b)) 6 | ) 7 | ) 8 | (define 9 | -= 10 | (macro 11 | (a b) 12 | (define a (- a b)) 13 | ) 14 | ) 15 | (define 16 | *= 17 | (macro 18 | (a b) 19 | (define a (* a b)) 20 | ) 21 | ) 22 | (define 23 | /= 24 | (macro 25 | (a b) 26 | (define a (/ a b)) 27 | ) 28 | ) 29 | (define 30 | %= 31 | (macro 32 | (a b) 33 | (define a (% a b)) 34 | ) 35 | ) 36 | (define 37 | generator 38 | (macro 39 | (p q) 40 | (i o) 41 | (define 42 | p 43 | (each 44 | (define i (chan)) 45 | (define o (chan)) 46 | (define 47 | (yield n) 48 | (each 49 | (o n) 50 | (i) 51 | ) 52 | ) 53 | (define p q) 54 | (go 55 | (each 56 | (i) 57 | p 58 | (close i) 59 | (close o) 60 | ) 61 | ) 62 | (lambda 63 | () 64 | (if 65 | (catch 66 | (each 67 | (i 1) 68 | (define x (o)) 69 | ) 70 | ) 71 | (raise "nothing to yield") 72 | x 73 | ) 74 | ) 75 | ) 76 | ) 77 | ) 78 | ) 79 | (define 80 | trace 81 | (macro 82 | (p q) 83 | (define 84 | p 85 | (each 86 | (print "call (" (car (quote p))) 87 | (for 88 | i 89 | (cdr (quote p)) 90 | (print " " (eval i)) 91 | ) 92 | (println ")") 93 | q 94 | ) 95 | ) 96 | ) 97 | ) 98 | (define 99 | rewrite 100 | (macro 101 | (m f) 102 | (l) 103 | (eval 104 | (cons 105 | (quote define) 106 | (cons 107 | (car (quote f)) 108 | (cons 109 | ( 110 | (lambda 111 | () 112 | (each 113 | (define 114 | l 115 | (eval (car (quote f))) 116 | ) 117 | (m 118 | f 119 | (eval 120 | (cons 121 | l 122 | (cdr (quote f)) 123 | ) 124 | ) 125 | ) 126 | ) 127 | ) 128 | ) 129 | () 130 | ) 131 | ) 132 | ) 133 | ) 134 | ) 135 | ) 136 | (quote "ok") -------------------------------------------------------------------------------- /example/math.lsp: -------------------------------------------------------------------------------- 1 | (define 2 | (P m n) 3 | (if 4 | (or (> m n) (< m 0)) 5 | (raise "make sure 0 <= m <= n") 6 | (each 7 | (define s 1) 8 | (loop 9 | (define i m) 10 | (< i n) 11 | (each 12 | (define i (+ i 1)) 13 | (define s (* s i)) 14 | ) 15 | ) 16 | s 17 | ) 18 | ) 19 | ) 20 | (define 21 | (C m n) 22 | (if 23 | (or (> m n) (< m 0)) 24 | (raise "make sure 0 <= m <= n") 25 | (each 26 | (define s (P m n)) 27 | (loop 28 | (define i (+ (- n m) 1)) 29 | (> i 1) 30 | (each 31 | (define i (- i 1)) 32 | (define s (/ s i)) 33 | ) 34 | ) 35 | s 36 | ) 37 | ) 38 | ) 39 | (define 40 | (abs x) 41 | (if 42 | (< x 0) 43 | (- 0 x) 44 | x 45 | ) 46 | ) 47 | (define 48 | sum 49 | (omission 50 | (lambda 51 | (x y) 52 | (each 53 | (loop 54 | () 55 | (not (atom y)) 56 | (each 57 | (define z (car y)) 58 | (define y (cdr y)) 59 | (define x (+ x z)) 60 | ) 61 | ) 62 | x 63 | ) 64 | ) 65 | ) 66 | ) 67 | (define 68 | max 69 | (omission 70 | (lambda 71 | (x y) 72 | (each 73 | (loop 74 | () 75 | (not (atom y)) 76 | (each 77 | (define z (car y)) 78 | (define y (cdr y)) 79 | (if 80 | (< x z) 81 | (define x z) 82 | ) 83 | ) 84 | ) 85 | x 86 | ) 87 | ) 88 | ) 89 | ) 90 | (define 91 | min 92 | (omission 93 | (lambda 94 | (x y) 95 | (each 96 | (loop 97 | () 98 | (not (atom y)) 99 | (each 100 | (define z (car y)) 101 | (define y (cdr y)) 102 | (if 103 | (> x z) 104 | (define x z) 105 | ) 106 | ) 107 | ) 108 | x 109 | ) 110 | ) 111 | ) 112 | ) 113 | (quote "ok") -------------------------------------------------------------------------------- /example/omission.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/hydra13142/lisp" 4 | 5 | func main() { 6 | console := lisp.NewLisp() 7 | console.Eval([]byte(` 8 | (each 9 | (define 10 | (g x y) 11 | (cons x y) 12 | ) 13 | (define 14 | G 15 | (omission g) 16 | ) 17 | (println 18 | (G 3) 19 | ) 20 | (println 21 | (G 3 2) 22 | ) 23 | (println 24 | (G 3 2 1) 25 | ) 26 | ) 27 | `)) 28 | } -------------------------------------------------------------------------------- /example/sort.lsp: -------------------------------------------------------------------------------- 1 | (load "list") 2 | (define 3 | (QuickSort s) 4 | (if 5 | (atom s) 6 | s 7 | (each 8 | (define n (car s)) 9 | (define 10 | a 11 | (filter 12 | s 13 | (lambda (x) (< x n)) 14 | ) 15 | ) 16 | (define 17 | b 18 | (filter 19 | s 20 | (lambda (x) (== x n)) 21 | ) 22 | ) 23 | (define 24 | c 25 | (filter 26 | s 27 | (lambda (x) (> x n)) 28 | ) 29 | ) 30 | (+ (+ (self a) b) (self c)) 31 | ) 32 | ) 33 | ) 34 | (define 35 | (BubbleSort l) 36 | (each 37 | (define 38 | (min n) 39 | (if 40 | (atom n) 41 | () 42 | (each 43 | (define x (car n)) 44 | (define y (self (cdr n))) 45 | (if 46 | (atom y) 47 | (cons x ()) 48 | (each 49 | (define z (car y)) 50 | (if 51 | (<= x z) 52 | (cons x y) 53 | (cons z (cons x (cdr y))) 54 | ) 55 | ) 56 | ) 57 | ) 58 | ) 59 | ) 60 | (if 61 | (atom l) 62 | () 63 | (each 64 | (define s (min l)) 65 | (cons (car s) (self (cdr s))) 66 | ) 67 | ) 68 | ) 69 | ) 70 | (define 71 | (MergeSort l) 72 | (each 73 | (define 74 | (make l) 75 | (if 76 | (atom l) 77 | () 78 | (cons 79 | (cons (car l) ()) 80 | (self (cdr l)) 81 | ) 82 | ) 83 | ) 84 | (define 85 | (reduce l) 86 | (if 87 | (atom l) 88 | l 89 | (each 90 | (define x (car l)) 91 | (define p (cdr l)) 92 | (if 93 | (atom p) 94 | l 95 | (each 96 | (define y (car p)) 97 | (define p (cdr p)) 98 | (cons 99 | (merge x y) 100 | (self p) 101 | ) 102 | ) 103 | ) 104 | ) 105 | ) 106 | ) 107 | (if 108 | (atom l) 109 | () 110 | (each 111 | (define L (make l)) 112 | (until 113 | (atom (cdr L)) 114 | (define L (reduce L)) 115 | ) 116 | (car L) 117 | ) 118 | ) 119 | ) 120 | ) 121 | (quote "ok") 122 | -------------------------------------------------------------------------------- /example/yield.lsp: -------------------------------------------------------------------------------- 1 | (load "list") 2 | (define 3 | infinite 4 | (default 5 | (lambda 6 | (n t) 7 | (each 8 | (define n (- n t)) 9 | (lambda 10 | () 11 | (update n (+ n t)) 12 | ) 13 | ) 14 | ) 15 | 0 16 | 1 17 | ) 18 | ) 19 | (define 20 | (iterator n f) 21 | (lambda 22 | () 23 | (each 24 | (define x n) 25 | (update n (f n)) 26 | x 27 | ) 28 | ) 29 | ) 30 | (define 31 | (fbnq) 32 | (each 33 | (define a 0) 34 | (define b 1) 35 | (lambda 36 | () 37 | (each 38 | (define c a) 39 | (update a b) 40 | (update b (+ a c)) 41 | a 42 | ) 43 | ) 44 | ) 45 | ) 46 | (define 47 | (xrange a b) 48 | (each 49 | (define a (- a 1)) 50 | (lambda 51 | () 52 | (each 53 | (update a (+ a 1)) 54 | (if 55 | (< a b) 56 | a 57 | (raise "nothing to yield") 58 | ) 59 | ) 60 | ) 61 | ) 62 | ) 63 | (define 64 | every 65 | (omission 66 | (lambda 67 | (l) 68 | (each 69 | (define l (plain l)) 70 | (lambda 71 | () 72 | (if 73 | (atom l) 74 | (raise "nothing to yield") 75 | (each 76 | (define y (car l)) 77 | (update l (cdr l)) 78 | y 79 | ) 80 | ) 81 | ) 82 | ) 83 | ) 84 | ) 85 | ) 86 | (define 87 | combine 88 | (omission 89 | (lambda 90 | (l) 91 | (lambda 92 | () 93 | (each 94 | (if 95 | (atom l) 96 | (raise "nothing to yield") 97 | ) 98 | (define 99 | t 100 | (catch 101 | (define 102 | x 103 | ((car l)) 104 | ) 105 | ) 106 | ) 107 | (if 108 | t 109 | (each 110 | (update l (cdr l)) 111 | (self) 112 | ) 113 | x 114 | ) 115 | ) 116 | ) 117 | ) 118 | ) 119 | ) 120 | (quote "ok") -------------------------------------------------------------------------------- /feed.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | ) 7 | 8 | func Scan(s []byte) (list []Token, err error) { 9 | scanner := pattern.NewScanner(s, true) 10 | list = make([]Token, 0, 100) 11 | for { 12 | a, b, c := scanner.Scan() 13 | if c != nil { 14 | break 15 | } 16 | switch b { 17 | case 1: 18 | list = append(list, Token{Operator, a}) 19 | case 2: 20 | list = append(list, Token{Int, a}) 21 | case 3: 22 | list = append(list, Token{Float, a}) 23 | case 4: 24 | list = append(list, Token{Int, a}) 25 | case 5: 26 | list = append(list, Token{String, a}) 27 | case 6: 28 | list = append(list, Token{Label, a}) 29 | } 30 | } 31 | if !scanner.Over() { 32 | err = ErrNotOver 33 | } 34 | return 35 | } 36 | 37 | func Tree(tkn []Token) ([]Token, error) { 38 | var f Token 39 | var s int 40 | if len(tkn) == 0 { 41 | return nil, nil 42 | } 43 | if tkn[0].Kind == Operator { 44 | var t bool 45 | switch tkn[0].Text.(byte) { 46 | case '(': 47 | t = true 48 | case '[': 49 | t = false 50 | default: 51 | return nil, ErrUnquote 52 | } 53 | i, j, l := 1, 1, len(tkn) 54 | for i < l && j > 0 { 55 | if tkn[i].Kind == Operator { 56 | switch tkn[i].Text.(byte) { 57 | case '(', '[': 58 | j++ 59 | case ')': 60 | j-- 61 | } 62 | } 63 | i++ 64 | } 65 | if j <= 0 { 66 | fold, err := Tree(tkn[1 : i-1]) 67 | if err != nil { 68 | return nil, err 69 | } 70 | if t { 71 | f = Token{Text: fold, Kind: List} 72 | } else { 73 | f = Token{Text: fold, Kind: Fold} 74 | } 75 | s = i 76 | } else { 77 | return nil, ErrUnquote 78 | } 79 | } else { 80 | f = tkn[0] 81 | s = 1 82 | } 83 | rest, err := Tree(tkn[s:]) 84 | if err != nil { 85 | return nil, err 86 | } 87 | ans := make([]Token, 1+len(rest)) 88 | ans[0] = f 89 | copy(ans[1:], rest) 90 | return ans, nil 91 | } 92 | 93 | func Collect(c map[Name]bool, t *Token) { 94 | switch t.Kind { 95 | case List: 96 | for _, u := range t.Text.([]Token) { 97 | Collect(c, &u) 98 | } 99 | case Label: 100 | c[t.Text.(Name)] = true 101 | } 102 | } 103 | 104 | func TmpName() Name { 105 | u := [16]byte{'_'} 106 | for i := 1; i < 16; i++ { 107 | switch x := rand.Uint32() % 63; { 108 | case x < 26: 109 | u[i] = byte(x + 'A') 110 | case x < 52: 111 | u[i] = byte(x + 'a' - 26) 112 | case x < 62: 113 | u[i] = byte(x + '0' - 52) 114 | default: 115 | u[i] = '_' 116 | } 117 | } 118 | return Name(string(u[:])) 119 | } 120 | 121 | func Repl(tkn Token, lst map[Name]Token) Token { 122 | switch tkn.Kind { 123 | case List: 124 | l := tkn.Text.([]Token) 125 | x := make([]Token, len(l)) 126 | for i, t := range l { 127 | x[i] = Repl(t, lst) 128 | } 129 | return Token{List, x} 130 | case Label: 131 | t, ok := lst[tkn.Text.(Name)] 132 | if ok { 133 | return t 134 | } 135 | } 136 | return tkn 137 | } 138 | 139 | func Hard(tkn Token) Token { 140 | switch tkn.Kind { 141 | case List: 142 | l := tkn.Text.([]Token) 143 | x := make([]Token, len(l)) 144 | for i, t := range l { 145 | x[i] = Hard(t) 146 | } 147 | return Token{List, x} 148 | case Label: 149 | t, ok := Global.env[tkn.Text.(Name)] 150 | if ok { 151 | return t 152 | } 153 | case Macro: 154 | m := tkn.Text.(*Hong) 155 | l := m.Text 156 | x := make([]Token, len(l)) 157 | for i, t := range l { 158 | x[i] = Hard(t) 159 | } 160 | return Token{Macro, &Hong{m.Para, x, m.Real}} 161 | case Front: 162 | f := tkn.Text.(*Lfac) 163 | l := f.Text 164 | x := make([]Token, len(l)) 165 | for i, t := range l { 166 | x[i] = Hard(t) 167 | } 168 | return Token{Front, &Lfac{f.Para, x, f.Make}} 169 | } 170 | return tkn 171 | } 172 | 173 | func init() { 174 | rand.Seed(time.Now().Unix()) 175 | } 176 | -------------------------------------------------------------------------------- /flow.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | func init() { 4 | Add("each", func(t []Token, p *Lisp) (ans Token, err error) { 5 | if len(t) == 0 { 6 | return None, ErrParaNum 7 | } 8 | for _, i := range t { 9 | ans, err = p.Exec(i) 10 | if err != nil { 11 | break 12 | } 13 | } 14 | return ans, err 15 | }) 16 | Add("block", func(t []Token, p *Lisp) (ans Token, err error) { 17 | if len(t) == 0 { 18 | return None, ErrParaNum 19 | } 20 | q := &Lisp{dad: p, env: map[Name]Token{}} 21 | for _, i := range t { 22 | ans, err = q.Exec(i) 23 | if err != nil { 24 | break 25 | } 26 | } 27 | return ans, err 28 | }) 29 | Add("if", func(t []Token, p *Lisp) (Token, error) { 30 | if len(t) < 2 || len(t) > 3 { 31 | return None, ErrParaNum 32 | } 33 | ans, err := p.Exec(t[0]) 34 | if err != nil { 35 | return None, err 36 | } 37 | if ans.Bool() { 38 | return p.Exec(t[1]) 39 | } 40 | if len(t) == 3 { 41 | return p.Exec(t[2]) 42 | } 43 | return None, nil 44 | }) 45 | Add("cond", func(t []Token, p *Lisp) (Token, error) { 46 | if len(t) == 0 { 47 | return None, ErrParaNum 48 | } 49 | for _, i := range t { 50 | if i.Kind != List { 51 | return None, ErrFitType 52 | } 53 | t := i.Text.([]Token) 54 | if len(t) != 2 { 55 | return None, ErrParaNum 56 | } 57 | ans, err := p.Exec(t[0]) 58 | if err != nil { 59 | return None, err 60 | } 61 | if ans.Bool() { 62 | return p.Exec(t[1]) 63 | } 64 | } 65 | return None, nil 66 | }) 67 | Add("while", func(t []Token, p *Lisp) (Token, error) { 68 | if len(t) != 2 { 69 | return None, ErrParaNum 70 | } 71 | for { 72 | a, err := p.Exec(t[0]) 73 | if err != nil { 74 | return None, err 75 | } 76 | if !a.Bool() { 77 | break 78 | } 79 | _, err = p.Exec(t[1]) 80 | if err != nil { 81 | return None, err 82 | } 83 | } 84 | return None, nil 85 | }) 86 | Add("until", func(t []Token, p *Lisp) (Token, error) { 87 | if len(t) != 2 { 88 | return None, ErrParaNum 89 | } 90 | for { 91 | a, err := p.Exec(t[0]) 92 | if err != nil { 93 | return None, err 94 | } 95 | if a.Bool() { 96 | break 97 | } 98 | _, err = p.Exec(t[1]) 99 | if err != nil { 100 | return None, err 101 | } 102 | } 103 | return None, nil 104 | }) 105 | Add("loop", func(t []Token, p *Lisp) (Token, error) { 106 | if len(t) != 3 { 107 | return None, ErrParaNum 108 | } 109 | _, err := p.Exec(t[0]) 110 | if err != nil { 111 | return None, err 112 | } 113 | for { 114 | a, err := p.Exec(t[1]) 115 | if err != nil { 116 | return None, err 117 | } 118 | if !a.Bool() { 119 | break 120 | } 121 | _, err = p.Exec(t[2]) 122 | if err != nil { 123 | return None, err 124 | } 125 | } 126 | return None, nil 127 | }) 128 | Add("for", func(t []Token, p *Lisp) (Token, error) { 129 | if len(t) != 3 { 130 | return None, ErrParaNum 131 | } 132 | if t[0].Kind != Label { 133 | return None, ErrFitType 134 | } 135 | iter, err := p.Exec(t[1]) 136 | if err != nil { 137 | return None, err 138 | } 139 | if iter.Kind != List { 140 | return None, ErrFitType 141 | } 142 | n := t[0].Text.(Name) 143 | for _, m := range iter.Text.([]Token) { 144 | p.env[n] = m 145 | _, err = p.Exec(t[2]) 146 | if err != nil { 147 | return None, err 148 | } 149 | } 150 | return None, nil 151 | }) 152 | } 153 | -------------------------------------------------------------------------------- /io.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | func init() { 10 | Add("scan", func(t []Token, p *Lisp) (Token, error) { 11 | if len(t) != 0 { 12 | return None, ErrParaNum 13 | } 14 | buf := bufio.NewReader(os.Stdin) 15 | one := section{} 16 | for { 17 | data, err := buf.ReadBytes('\n') 18 | if err != nil { 19 | return None, err 20 | } 21 | err = one.feed(data) 22 | if err != nil { 23 | return None, err 24 | } 25 | if one.over() { 26 | break 27 | } 28 | } 29 | return p.Eval([]byte(one.total)) 30 | }) 31 | Add("load", func(t []Token, p *Lisp) (Token, error) { 32 | if len(t) != 1 { 33 | return None, ErrParaNum 34 | } 35 | if t[0].Kind != String { 36 | return None, ErrFitType 37 | } 38 | return p.Load(t[0].Text.(string)) 39 | }) 40 | Add("print", func(t []Token, p *Lisp) (x Token, y error) { 41 | for _, i := range t { 42 | x, y = p.Exec(i) 43 | if y != nil { 44 | return None, y 45 | } 46 | fmt.Print(x) 47 | } 48 | return x, nil 49 | }) 50 | Add("println", func(t []Token, p *Lisp) (x Token, y error) { 51 | for _, i := range t { 52 | x, y = p.Exec(i) 53 | if y != nil { 54 | return None, y 55 | } 56 | fmt.Println(x) 57 | } 58 | return x, nil 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /label.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | func init() { 4 | Add("builtin", func(t []Token, p *Lisp) (Token, error) { 5 | if len(t) != 1 { 6 | return None, ErrParaNum 7 | } 8 | if t[0].Kind != Label { 9 | return None, ErrFitType 10 | } 11 | ans, ok := Global.env[t[0].Text.(Name)] 12 | if !ok { 13 | return None, ErrNotFind 14 | } 15 | return ans, nil 16 | }) 17 | Add("define", func(t []Token, p *Lisp) (ans Token, err error) { 18 | if len(t) != 2 { 19 | return None, ErrParaNum 20 | } 21 | a, b := t[0], t[1] 22 | switch a.Kind { 23 | case Label: 24 | ans, err = p.Exec(b) 25 | if err == nil { 26 | p.env[a.Text.(Name)] = ans 27 | } 28 | return ans, err 29 | case List: 30 | if b.Kind != List { 31 | return None, ErrFitType 32 | } 33 | t = a.Text.([]Token) 34 | if len(t) <= 0 { 35 | return None, ErrParaNum 36 | } 37 | x := make([]Name, len(t)) 38 | for i, c := range t { 39 | if c.Kind != Label { 40 | return None, ErrNotName 41 | } 42 | x[i] = c.Text.(Name) 43 | } 44 | ans = Token{Front, &Lfac{x[1:], b.Text.([]Token), p}} 45 | p.env[x[0]] = ans 46 | return ans, nil 47 | } 48 | return None, ErrFitType 49 | }) 50 | Add("update", func(t []Token, p *Lisp) (ans Token, err error) { 51 | if len(t) != 2 { 52 | return None, ErrParaNum 53 | } 54 | a, b := t[0], t[1] 55 | var n Name 56 | switch a.Kind { 57 | case Label: 58 | n = a.Text.(Name) 59 | case List: 60 | if b.Kind != List { 61 | return None, ErrFitType 62 | } 63 | t = a.Text.([]Token) 64 | if len(t) <= 0 { 65 | return None, ErrParaNum 66 | } 67 | n = t[0].Text.(Name) 68 | default: 69 | return None, ErrFitType 70 | } 71 | for v := p; p != Global; p = p.dad { 72 | _, ok := p.env[n] 73 | if ok { 74 | if a.Kind == Label { 75 | ans, err = p.Exec(b) 76 | if err == nil { 77 | p.env[n] = ans 78 | } 79 | return ans, err 80 | } else { 81 | x := make([]Name, len(t)-1) 82 | for i, c := range t[1:] { 83 | if c.Kind != Label { 84 | return None, ErrNotName 85 | } 86 | x[i] = c.Text.(Name) 87 | } 88 | ans = Token{Front, &Lfac{x, b.Text.([]Token), p}} 89 | v.env[n] = ans 90 | return ans, nil 91 | } 92 | } 93 | } 94 | _, ok := p.env[n] 95 | if !ok { 96 | return None, ErrNotFind 97 | } 98 | return None, ErrRefused 99 | }) 100 | Add("remove", func(t []Token, p *Lisp) (ans Token, err error) { 101 | if len(t) != 1 { 102 | return None, ErrParaNum 103 | } 104 | if t[0].Kind != Label { 105 | return None, ErrFitType 106 | } 107 | n := t[0].Text.(Name) 108 | for ; p != Global; p = p.dad { 109 | _, ok := p.env[n] 110 | if ok { 111 | delete(p.env, n) 112 | return None, nil 113 | } 114 | } 115 | _, ok := p.env[n] 116 | if !ok { 117 | return None, ErrNotFind 118 | } 119 | return None, ErrRefused 120 | }) 121 | Add("present", func(t []Token, p *Lisp) (ans Token, err error) { 122 | if len(t) != 0 { 123 | return None, ErrParaNum 124 | } 125 | x := make([]Token, 0, len(p.env)) 126 | for i, _ := range p.env { 127 | x = append(x, Token{Label, i}) 128 | } 129 | return Token{List, x}, nil 130 | }) 131 | Add("context", func(t []Token, p *Lisp) (ans Token, err error) { 132 | if len(t) != 0 { 133 | return None, ErrParaNum 134 | } 135 | x := make([]Token, 0, 128) 136 | for v := p; v != nil; v = v.dad { 137 | for i, _ := range v.env { 138 | x = append(x, Token{Label, i}) 139 | } 140 | } 141 | return Token{List, x}, nil 142 | }) 143 | Add("clear", func(t []Token, p *Lisp) (ans Token, err error) { 144 | if len(t) != 0 { 145 | return None, ErrParaNum 146 | } 147 | p.env = map[Name]Token{} 148 | return None, nil 149 | }) 150 | } 151 | -------------------------------------------------------------------------------- /lisp.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "io/ioutil" 9 | "os" 10 | ) 11 | 12 | type Lisp struct { 13 | dad *Lisp 14 | env map[Name]Token 15 | } 16 | 17 | func NewLisp() *Lisp { 18 | x := new(Lisp) 19 | x.env = map[Name]Token{} 20 | x.dad = Global 21 | return x 22 | } 23 | 24 | func Add(s string, f func([]Token, *Lisp) (Token, error)) { 25 | Global.env[Name(s)] = Token{Back, Gfac(f)} 26 | } 27 | 28 | func (l *Lisp) Exec(f Token) (ans Token, err error) { 29 | var ( 30 | ls []Token 31 | ct Token 32 | ok bool 33 | ) 34 | switch f.Kind { 35 | case Fold: 36 | return Token{List, f.Text.([]Token)}, nil 37 | case Label: 38 | nm := f.Text.(Name) 39 | for ; l != nil; l = l.dad { 40 | ct, ok = l.env[nm] 41 | if ok { 42 | return ct, nil 43 | } 44 | } 45 | return None, ErrNotFind 46 | case List: 47 | ls = f.Text.([]Token) 48 | if len(ls) == 0 { 49 | return False, nil 50 | } 51 | ct = ls[0] 52 | switch ct.Kind { 53 | case Label: 54 | nm := ct.Text.(Name) 55 | for v := l; v != nil; v = v.dad { 56 | ct, ok = v.env[nm] 57 | if ok { 58 | break 59 | } 60 | } 61 | if !ok { 62 | return None, ErrNotFind 63 | } 64 | case List: 65 | ct, err = l.Exec(ct) 66 | if err != nil { 67 | return None, err 68 | } 69 | } 70 | switch ct.Kind { 71 | case Chan: 72 | switch len(ls) { 73 | case 1: 74 | u, ok := <-ct.Text.(chan Token) 75 | if ok { 76 | return u, nil 77 | } else { 78 | return None, ErrIsClose 79 | } 80 | case 2: 81 | u, err := l.Exec(ls[1]) 82 | if err != nil { 83 | return None, err 84 | } 85 | t := func() (s string) { 86 | defer func() { 87 | e := recover() 88 | if e != nil { 89 | s = fmt.Sprint(e) 90 | } 91 | }() 92 | ct.Text.(chan Token) <- u 93 | return 94 | }() 95 | if t != "" { 96 | return None, errors.New(t) 97 | } 98 | return u, nil 99 | default: 100 | return None, ErrParaNum 101 | } 102 | case Back: 103 | return ct.Text.(Gfac)(ls[1:], l) 104 | case Macro: 105 | mp := ct.Text.(*Hong) 106 | if len(ls) != len(mp.Para)+1 { 107 | return None, ErrParaNum 108 | } 109 | xp := map[Name]Token{} 110 | for i, t := range ls[1:] { 111 | xp[mp.Para[i]] = t 112 | } 113 | if mp.Real == nil { 114 | for i, t := range mp.Para { 115 | xp[t] = ls[1+i] 116 | } 117 | } else { 118 | cp := map[Name]bool{} 119 | for i, t := range ls[1:] { 120 | xp[mp.Para[i]] = t 121 | Collect(cp, &t) 122 | } 123 | for _, t := range mp.Real { 124 | var i Name 125 | for { 126 | i = TmpName() 127 | _, ok := cp[i] 128 | if !ok { 129 | break 130 | } 131 | } 132 | xp[t] = Token{Label, i} 133 | } 134 | } 135 | return l.Exec(Repl(Token{List, mp.Text}, xp)) 136 | case Front: 137 | lp := ct.Text.(*Lfac) 138 | if len(ls) != len(lp.Para)+1 { 139 | return None, ErrParaNum 140 | } 141 | q := &Lisp{dad: lp.Make, env: map[Name]Token{}} 142 | q.env[Name("self")] = ct 143 | for i, t := range ls[1:] { 144 | q.env[lp.Para[i]], err = l.Exec(t) 145 | if err != nil { 146 | return None, err 147 | } 148 | } 149 | return q.Exec(Token{List, lp.Text}) 150 | default: 151 | return None, ErrNotFunc 152 | } 153 | default: 154 | return f, nil 155 | } 156 | return None, nil 157 | } 158 | 159 | func (l *Lisp) Eval(s []byte) (Token, error) { 160 | var ( 161 | a, b []Token 162 | c, d Token 163 | e error 164 | ) 165 | a, e = Scan(s) 166 | if e != nil { 167 | return None, e 168 | } 169 | b, e = Tree(a) 170 | if e != nil { 171 | return None, e 172 | } 173 | for _, c = range b { 174 | d, e = l.Exec(c) 175 | if e != nil { 176 | return None, e 177 | } 178 | } 179 | return d, nil 180 | } 181 | 182 | func (l *Lisp) Load(s string) (Token, error) { 183 | var file *os.File 184 | var data []byte 185 | var err error 186 | file, err = os.Open(s) 187 | if err != nil { 188 | file, err = os.Open(s + ".lsp") 189 | if err != nil { 190 | return None, err 191 | } 192 | } 193 | defer file.Close() 194 | data, err = ioutil.ReadAll(file) 195 | if err != nil { 196 | return None, err 197 | } 198 | buf := bytes.NewBuffer(data) 199 | one := section{} 200 | for { 201 | data, err := buf.ReadBytes('\n') 202 | if err != nil { 203 | if err != io.EOF { 204 | return None, err 205 | } 206 | err = one.feed(data) 207 | break 208 | } 209 | err = one.feed(data) 210 | if err != nil { 211 | return None, err 212 | } 213 | } 214 | if !one.over() { 215 | return None, ErrUnquote 216 | } 217 | return l.Eval([]byte(one.total)) 218 | } 219 | -------------------------------------------------------------------------------- /logic.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | func init() { 4 | Add("and", func(t []Token, p *Lisp) (Token, error) { 5 | if len(t) != 2 { 6 | return None, ErrParaNum 7 | } 8 | x, err := p.Exec(t[0]) 9 | if err != nil { 10 | return None, err 11 | } 12 | if !x.Bool() { 13 | return None, nil 14 | } 15 | y, err := p.Exec(t[1]) 16 | if err != nil { 17 | return None, err 18 | } 19 | if y.Bool() { 20 | return True, nil 21 | } else { 22 | return False, nil 23 | } 24 | }) 25 | Add("or", func(t []Token, p *Lisp) (Token, error) { 26 | if len(t) != 2 { 27 | return None, ErrParaNum 28 | } 29 | x, err := p.Exec(t[0]) 30 | if err != nil { 31 | return None, err 32 | } 33 | if x.Bool() { 34 | return True, nil 35 | } 36 | y, err := p.Exec(t[1]) 37 | if err != nil { 38 | return None, err 39 | } 40 | if y.Bool() { 41 | return True, nil 42 | } else { 43 | return False, nil 44 | } 45 | }) 46 | Add("xor", func(t []Token, p *Lisp) (Token, error) { 47 | if len(t) != 2 { 48 | return None, ErrParaNum 49 | } 50 | x, err := p.Exec(t[0]) 51 | if err != nil { 52 | return None, err 53 | } 54 | y, err := p.Exec(t[1]) 55 | if err != nil { 56 | return None, err 57 | } 58 | if x.Bool() != y.Bool() { 59 | return True, nil 60 | } else { 61 | return False, nil 62 | } 63 | }) 64 | Add("not", func(t []Token, p *Lisp) (Token, error) { 65 | if len(t) != 1 { 66 | return None, ErrParaNum 67 | } 68 | x, err := p.Exec(t[0]) 69 | if err != nil { 70 | return None, err 71 | } 72 | if x.Bool() { 73 | return False, nil 74 | } else { 75 | return True, nil 76 | } 77 | }) 78 | } 79 | -------------------------------------------------------------------------------- /math/math.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "github.com/hydra13142/lisp" 5 | "math" 6 | ) 7 | 8 | var ( 9 | Sin, Sinh, Asin, Asinh lisp.Gfac 10 | Cos, Cosh, Acos, Acosh lisp.Gfac 11 | Tan, Tanh, Atan, Atanh lisp.Gfac 12 | Exp, Log lisp.Gfac 13 | Sqrt lisp.Gfac 14 | Pow lisp.Gfac 15 | ) 16 | 17 | func Wrap1(f func(float64) float64) func([]lisp.Token, *lisp.Lisp) (lisp.Token, error) { 18 | return func(t []lisp.Token, p *lisp.Lisp) (lisp.Token, error) { 19 | if len(t) != 1 { 20 | return lisp.None, lisp.ErrParaNum 21 | } 22 | u, err := p.Exec(t[0]) 23 | if err != nil { 24 | return lisp.None, err 25 | } 26 | if u.Kind != lisp.Float { 27 | return lisp.None, lisp.ErrFitType 28 | } 29 | return lisp.Token{lisp.Float, f(u.Text.(float64))}, nil 30 | } 31 | } 32 | 33 | func Wrap2(f func(float64, float64) float64) func([]lisp.Token, *lisp.Lisp) (lisp.Token, error) { 34 | return func(t []lisp.Token, p *lisp.Lisp) (lisp.Token, error) { 35 | if len(t) != 2 { 36 | return lisp.None, lisp.ErrParaNum 37 | } 38 | u, err := p.Exec(t[0]) 39 | if err != nil { 40 | return lisp.None, err 41 | } 42 | if u.Kind != lisp.Float { 43 | return lisp.None, lisp.ErrFitType 44 | } 45 | v, err := p.Exec(t[1]) 46 | if err != nil { 47 | return lisp.None, err 48 | } 49 | if v.Kind != lisp.Float { 50 | return lisp.None, lisp.ErrFitType 51 | } 52 | return lisp.Token{lisp.Float, f(u.Text.(float64), v.Text.(float64))}, nil 53 | } 54 | } 55 | 56 | func init() { 57 | Sin, Sinh, Asin, Asinh = Wrap1(math.Sin), Wrap1(math.Sinh), Wrap1(math.Asin), Wrap1(math.Asinh) 58 | Cos, Cosh, Acos, Acosh = Wrap1(math.Cos), Wrap1(math.Cosh), Wrap1(math.Acos), Wrap1(math.Acosh) 59 | Tan, Tanh, Atan, Atanh = Wrap1(math.Tan), Wrap1(math.Tanh), Wrap1(math.Atan), Wrap1(math.Atanh) 60 | Exp, Log = Wrap1(math.Exp), Wrap1(math.Log) 61 | Sqrt = Wrap1(math.Sqrt) 62 | Pow = Wrap2(math.Pow) 63 | } 64 | -------------------------------------------------------------------------------- /parser/example/calc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/hydra13142/parser" 6 | ) 7 | 8 | var express = &parser.Pattern{} 9 | 10 | func init() { 11 | express.Add(func(s []byte) (interface{}, int) { 12 | switch s[0] { 13 | case '+', '-', '*', '/', '(', ')': 14 | return s[0], 1 15 | } 16 | return nil, 0 17 | }) 18 | express.Add(func(s []byte) (interface{}, int) { 19 | a, i := parser.ParseFloat(s) 20 | return a, i 21 | }) 22 | } 23 | 24 | func Calc(s string) (float64, error) { 25 | md := make([]float64, 32) 26 | op := make([]byte, 32) 27 | i, j := -1, -1 28 | 29 | cls := func(f func(byte) bool) bool { 30 | for j >= 0 && i >= 1 && f(op[j]) { 31 | switch op[j] { 32 | case '+': 33 | md[i-1] += md[i] 34 | i-- 35 | case '-': 36 | md[i-1] -= md[i] 37 | i-- 38 | case '*': 39 | md[i-1] *= md[i] 40 | i-- 41 | case '/': 42 | md[i-1] /= md[i] 43 | i-- 44 | } 45 | j-- 46 | } 47 | return j < 0 || !f(op[j]) 48 | } 49 | scanner := express.NewScanner([]byte(s), true) 50 | for { 51 | a, b, c := scanner.Scan() 52 | if c != nil { 53 | break 54 | } 55 | if b == 1 { 56 | switch t := a.(byte); t { 57 | case '(': 58 | j++ 59 | op[j] = t 60 | case ')': 61 | if !cls(func(c byte) bool { return c != '(' }) { 62 | return 0, fmt.Errorf("wrong") 63 | } 64 | j-- 65 | case '+', '-': 66 | if !cls(func(c byte) bool { return c != '(' }) { 67 | return 0, fmt.Errorf("wrong") 68 | } 69 | j++ 70 | op[j] = t 71 | case '*', '/': 72 | if !cls(func(c byte) bool { return c == '*' || c == '/' }) { 73 | return 0, fmt.Errorf("wrong") 74 | } 75 | j++ 76 | op[j] = t 77 | } 78 | } else { 79 | i++ 80 | md[i] = a.(float64) 81 | } 82 | } 83 | if !cls(func(_ byte) bool { return true }) { 84 | return 0, fmt.Errorf("wrong") 85 | } 86 | return md[0], nil 87 | } 88 | 89 | func main() { 90 | fmt.Println(Calc("1-2+3*4")) 91 | } 92 | -------------------------------------------------------------------------------- /parser/parse.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "bytes" 5 | "math" 6 | "unicode/utf8" 7 | ) 8 | 9 | func IsSpace(c byte) bool { 10 | return c == '\r' || c == '\n' || c == '\t' || c == '\v' || c == '\f' || c == ' ' 11 | } 12 | 13 | func IsDigit(c byte) bool { 14 | return c >= '0' && c <= '9' 15 | } 16 | 17 | func IsLower(c byte) bool { 18 | return c >= 'a' && c <= 'z' 19 | } 20 | 21 | func IsUpper(c byte) bool { 22 | return c >= 'A' && c <= 'Z' 23 | } 24 | 25 | func IsAlpha(c byte) bool { 26 | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') 27 | } 28 | 29 | func IsFirst(c byte) bool { 30 | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' 31 | } 32 | 33 | func IsLetter(c byte) bool { 34 | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' 35 | } 36 | 37 | func ParseOct(r []byte, L int) (i int64, l int) { 38 | var c byte 39 | for l, c = range r { 40 | if l >= L || c < '0' || c > '7' { 41 | return 42 | } 43 | i = i*8 + int64(c-'0') 44 | } 45 | l++ 46 | return 47 | } 48 | 49 | func ParseDec(r []byte, L int) (i int64, l int) { 50 | var c byte 51 | for l, c = range r { 52 | if l >= L || c < '0' || c > '9' { 53 | return 54 | } 55 | i = i*10 + int64(c-'0') 56 | } 57 | l++ 58 | return 59 | } 60 | 61 | func ParseHex(r []byte, L int) (i int64, l int) { 62 | var c byte 63 | for l, c = range r { 64 | if l >= L { 65 | return 66 | } 67 | switch { 68 | case c >= '0' && c <= '9': 69 | i = i*16 + int64(c-'0') 70 | case c >= 'A' && c <= 'Z': 71 | i = i*16 + int64(c-'A'+10) 72 | case c >= 'a' && c <= 'z': 73 | i = i*16 + int64(c-'a'+10) 74 | default: 75 | return 76 | } 77 | } 78 | l++ 79 | return 80 | } 81 | 82 | func ParseInt(r []byte) (i int64, l int) { 83 | if len(r) == 0 { 84 | return 85 | } 86 | c, t := false, 0 87 | switch r[0] { 88 | case '-': 89 | c, t = true, 1 90 | case '+': 91 | t = 1 92 | } 93 | a, j := ParseDec(r[t:], 16) 94 | if j > 0 { 95 | if c { 96 | i = -a 97 | } else { 98 | i = a 99 | } 100 | l = j + t 101 | } 102 | return 103 | } 104 | 105 | func xiaoshu(r []byte) (f float64, l int) { 106 | var c byte 107 | if len(r) == 0 { 108 | return 109 | } 110 | if r[0] == '.' { 111 | i, j := 0, 1 112 | for l, c = range r[1:] { 113 | if c < '0' || c > '9' { 114 | break 115 | } 116 | i, j = i*10+int(c-'0'), j*10 117 | } 118 | if c >= '0' && c <= '9' { 119 | l++ 120 | } 121 | if l > 0 { 122 | f, l = float64(i)/float64(j), l+1 123 | } 124 | } 125 | return 126 | } 127 | 128 | func zhishu(r []byte) (i int64, l int) { 129 | if len(r) == 0 { 130 | return 131 | } 132 | if r[0] == 'e' || r[0] == 'E' { 133 | a, j := ParseInt(r[1:]) 134 | if j > 0 { 135 | i, l = a, j+1 136 | } 137 | } 138 | return 139 | } 140 | 141 | func ParseFloat(r []byte) (f float64, l int) { 142 | if len(r) == 0 { 143 | return 144 | } 145 | p, t := false, 0 146 | switch r[0] { 147 | case '-': 148 | p, t = true, 1 149 | case '+': 150 | t = 1 151 | } 152 | a, i := ParseDec(r[t:], 16) 153 | b, j := xiaoshu(r[t+i:]) 154 | c, k := zhishu(r[t+i+j:]) 155 | if i > 0 || j > 0 { 156 | f = float64(a) + b 157 | if k > 0 { 158 | f *= math.Pow10(int(c)) 159 | } 160 | if p { 161 | f = -f 162 | } 163 | l = t + i + j + k 164 | } 165 | return 166 | } 167 | 168 | func ParseChar(r []byte) (c rune, l int) { 169 | var i int64 170 | if len(r) > 0 { 171 | if r[0] == '\\' { 172 | if r[1] >= '0' && r[1] <= '7' { 173 | i, l = ParseOct(r[1:], 3) 174 | if i < 256 { 175 | return rune(i), l + 1 176 | } 177 | } else { 178 | l = 2 179 | switch r[1] { 180 | case 'x', 'X': 181 | i, l = ParseHex(r[2:], 2) 182 | if l != 2 { 183 | l = 0 184 | } else { 185 | l = 4 186 | } 187 | case 'u', 'U': 188 | i, l = ParseHex(r[2:], 4) 189 | if l != 4 { 190 | l = 0 191 | } else { 192 | l = 6 193 | } 194 | case 't': 195 | i = '\t' 196 | case 'r': 197 | i = '\r' 198 | case 'n': 199 | i = '\n' 200 | case 'v': 201 | i = '\v' 202 | case 'f': 203 | i = '\f' 204 | default: 205 | i = int64(r[1]) 206 | } 207 | if l != 0 { 208 | return rune(i), l 209 | } 210 | } 211 | } else { 212 | R := bytes.Runes(r) 213 | c = rune(R[0]) 214 | return c, utf8.RuneLen(c) 215 | } 216 | } 217 | return 0, 0 218 | } 219 | -------------------------------------------------------------------------------- /parser/type.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import "fmt" 4 | 5 | type Pattern struct { 6 | rule []func([]byte) (interface{}, int) 7 | str []string 8 | } 9 | 10 | type Scanner struct { 11 | ptn *Pattern 12 | tkn []byte 13 | skp bool 14 | } 15 | 16 | func (p *Pattern) Add(f func([]byte) (interface{}, int)) { 17 | p.rule = append(p.rule, f) 18 | } 19 | 20 | func (p *Pattern) AddString(s string) { 21 | p.str = append(p.str, s) 22 | } 23 | 24 | func (p *Pattern) NewScanner(s []byte, t bool) *Scanner { 25 | return &Scanner{ptn: p, tkn: s, skp: t} 26 | } 27 | 28 | func (s *Scanner) Skip() { 29 | i, l := 0, len(s.tkn) 30 | if l == 0 { 31 | return 32 | } 33 | for i < l && IsSpace(s.tkn[i]) { 34 | i++ 35 | } 36 | s.tkn = s.tkn[i:] 37 | } 38 | 39 | func (s *Scanner) Scan() (interface{}, int, error) { 40 | if s.skp { 41 | s.Skip() 42 | } 43 | if len(s.tkn) == 0 { 44 | return nil, 0, fmt.Errorf("empty string") 45 | } 46 | for i, t := range s.ptn.str { 47 | l := len(t) 48 | if len(s.tkn) >= l && t == string(s.tkn[:l]) { 49 | s.tkn = s.tkn[l:] 50 | return t, -(i + 1), nil 51 | } 52 | } 53 | for i, f := range s.ptn.rule { 54 | a, l := f(s.tkn) 55 | if l > 0 { 56 | s.tkn = s.tkn[l:] 57 | return a, +(i + 1), nil 58 | } 59 | } 60 | return nil, 0, fmt.Errorf("unrecognised") 61 | } 62 | 63 | func (s *Scanner) Over() bool { 64 | return len(s.tkn) == 0 65 | } 66 | -------------------------------------------------------------------------------- /pattern.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | import "github.com/hydra13142/lisp/parser" 4 | 5 | func init() { 6 | bnd := func(c byte) bool { 7 | return c == '(' || c == ')' || parser.IsSpace(c) 8 | } 9 | pattern.Add(func(s []byte) (interface{}, int) { 10 | if len(s) > 0 { 11 | switch s[0] { 12 | case '(', ')': 13 | return s[0], 1 14 | case '\'': 15 | if len(s) > 2 && s[1] == '(' && s[2] != '\'' { 16 | return byte('['), 2 17 | } 18 | } 19 | } 20 | return nil, 0 21 | }) 22 | pattern.Add(func(s []byte) (interface{}, int) { 23 | a, i := parser.ParseInt(s) 24 | if i > 0 { 25 | if _, j := parser.ParseFloat(s); i == j && (i >= len(s) || bnd(s[i])) { 26 | return a, i 27 | } 28 | } 29 | return nil, 0 30 | }) 31 | pattern.Add(func(s []byte) (interface{}, int) { 32 | a, i := parser.ParseFloat(s) 33 | if i > 0 && (i >= len(s) || bnd(s[i])) { 34 | return a, i 35 | } 36 | return nil, 0 37 | }) 38 | pattern.Add(func(s []byte) (interface{}, int) { 39 | if len(s) == 0 { 40 | return nil, 0 41 | } 42 | if s[0] == '\'' { 43 | a, i := parser.ParseChar(s[1:]) 44 | if i > 0 { 45 | i += 1 46 | if i < len(s) && s[i] == '\'' { 47 | i += 1 48 | if i >= len(s) || bnd(s[i]) { 49 | return int64(a), i 50 | } 51 | } 52 | } 53 | } 54 | return nil, 0 55 | }) 56 | pattern.Add(func(s []byte) (interface{}, int) { 57 | i := 1 58 | if len(s) == 0 || s[0] != '"' { 59 | return nil, 0 60 | } 61 | for ; i < len(s) && s[i] != '"'; i++ { 62 | if s[i] == '\\' { 63 | i++ 64 | } 65 | } 66 | if i < len(s) { 67 | a := string(s[1:i]) 68 | i += 1 69 | if i >= len(s) || bnd(s[i]) { 70 | return a, i 71 | } 72 | } 73 | return nil, 0 74 | }) 75 | pattern.Add(func(s []byte) (interface{}, int) { 76 | i := 0 77 | for i < len(s) && !bnd(s[i]) { 78 | i++ 79 | } 80 | a := Name(string(s[:i])) 81 | return a, i 82 | }) 83 | } 84 | -------------------------------------------------------------------------------- /section.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | type section struct { 4 | quote bool 5 | count int 6 | total string 7 | } 8 | 9 | func (b *section) feed(s []byte) error { 10 | single := false 11 | for i, l := 0, len(s); i < l; i++ { 12 | if b.quote { 13 | switch s[i] { 14 | case '"': 15 | b.quote = false 16 | case '\\': 17 | i++ 18 | } 19 | } else if single { 20 | switch s[i] { 21 | case '\'': 22 | single = false 23 | case '\\': 24 | i++ 25 | } 26 | } else { 27 | switch s[i] { 28 | case '(': 29 | b.count++ 30 | case ')': 31 | b.count-- 32 | case '\'': 33 | if i+1 < len(s) { 34 | if s[i+1] == '(' && (i+2 >= len(s) || s[i+2] != '\'') { 35 | b.count++ 36 | i++ 37 | } else { 38 | single = true 39 | } 40 | } 41 | case '"': 42 | b.quote = true 43 | case '#': 44 | s, l = s[:i], i 45 | } 46 | } 47 | } 48 | if single || b.count < 0 { 49 | return ErrUnquote 50 | } 51 | b.total += string(s) 52 | return nil 53 | } 54 | 55 | func (b *section) over() bool { 56 | return b.count == 0 && b.quote == false 57 | } 58 | -------------------------------------------------------------------------------- /token.go: -------------------------------------------------------------------------------- 1 | package lisp 2 | 3 | import "fmt" 4 | 5 | type Token struct { 6 | Kind 7 | Text interface{} 8 | } 9 | 10 | func (t *Token) Bool() bool { 11 | switch t.Kind { 12 | case Null: 13 | return false 14 | case Int: 15 | return t.Text.(int64) != 0 16 | case Float: 17 | return t.Text.(float64) != 0 18 | case String: 19 | return t.Text.(string) != "" 20 | case Chan: 21 | return len(t.Text.(chan Token)) != 0 22 | case List: 23 | return len(t.Text.([]Token)) != 0 24 | } 25 | return true 26 | } 27 | 28 | func (t *Token) Eq(p *Token) bool { 29 | var ( 30 | a, b []Token 31 | c, d []Name 32 | ) 33 | if t.Kind != p.Kind { 34 | return false 35 | } 36 | switch t.Kind { 37 | case Null: 38 | return true 39 | case Int: 40 | return t.Text.(int64) == p.Text.(int64) 41 | case Float: 42 | return t.Text.(float64) == p.Text.(float64) 43 | case String: 44 | return t.Text.(string) == p.Text.(string) 45 | case Back, Chan: 46 | return false 47 | case Label: 48 | return t.Text.(Name) == p.Text.(Name) 49 | case Front: 50 | if t.Text.(*Lfac).Make != p.Text.(*Lfac).Make { 51 | return false 52 | } 53 | a, b = t.Text.(*Lfac).Text, p.Text.(*Lfac).Text 54 | c, d = t.Text.(*Lfac).Para, p.Text.(*Lfac).Para 55 | case Macro: 56 | a, b = t.Text.(*Hong).Text, p.Text.(*Hong).Text 57 | c, d = t.Text.(*Hong).Para, p.Text.(*Hong).Para 58 | case Fold, List: 59 | a, b = t.Text.([]Token), p.Text.([]Token) 60 | c, d = nil, nil 61 | } 62 | m, n := len(a), len(b) 63 | if m != n { 64 | return false 65 | } 66 | for i := 0; i < m; i++ { 67 | if !a[i].Eq(&b[i]) { 68 | return false 69 | } 70 | } 71 | if c != nil { 72 | m, n := len(c), len(d) 73 | if m != n { 74 | return false 75 | } 76 | for i := 0; i < m; i++ { 77 | if c[i] != d[i] { 78 | return false 79 | } 80 | } 81 | } 82 | return true 83 | } 84 | 85 | func (t *Token) Cmp(p *Token) int { 86 | var a, b bool 87 | switch t.Kind { 88 | case Int: 89 | switch p.Kind { 90 | case Int: 91 | a = t.Text.(int64) > p.Text.(int64) 92 | b = t.Text.(int64) < p.Text.(int64) 93 | case Float: 94 | a = float64(t.Text.(int64)) > p.Text.(float64) 95 | b = float64(t.Text.(int64)) < p.Text.(float64) 96 | default: 97 | return 0 98 | } 99 | case Float: 100 | switch p.Kind { 101 | case Int: 102 | a = t.Text.(float64) > float64(p.Text.(int64)) 103 | b = t.Text.(float64) < float64(p.Text.(int64)) 104 | case Float: 105 | a = t.Text.(float64) > p.Text.(float64) 106 | b = t.Text.(float64) < p.Text.(float64) 107 | default: 108 | return 0 109 | } 110 | case String: 111 | switch p.Kind { 112 | case Int, Float: 113 | return 1 114 | case String: 115 | a = t.Text.(string) > p.Text.(string) 116 | b = t.Text.(string) < p.Text.(string) 117 | default: 118 | return 0 119 | } 120 | case List: 121 | switch p.Kind { 122 | case Int, Float, String: 123 | return 1 124 | case List: 125 | x, y := t.Text.([]Token), p.Text.([]Token) 126 | m, n := len(x), len(y) 127 | for i := 0; i < m && i < n; i++ { 128 | j := x[i].Cmp(&y[i]) 129 | if j != 0 { 130 | return j 131 | } 132 | } 133 | a = m > n 134 | b = m < n 135 | default: 136 | return 0 137 | } 138 | default: 139 | return 0 140 | } 141 | if a { 142 | return +1 143 | } 144 | if b { 145 | return -1 146 | } 147 | return 0 148 | } 149 | 150 | func (t Token) String() string { 151 | switch t.Kind { 152 | case Null: 153 | return "" 154 | case Chan: 155 | return "channel" 156 | default: 157 | return fmt.Sprint(t.Text) 158 | } 159 | } 160 | --------------------------------------------------------------------------------