Skip to content

Commit

Permalink
Builtins package is now part of eval package
Browse files Browse the repository at this point in the history
  • Loading branch information
brendantang committed Jul 26, 2021
1 parent 47d452d commit a99b610
Show file tree
Hide file tree
Showing 15 changed files with 274 additions and 229 deletions.
22 changes: 0 additions & 22 deletions builtins/let.go

This file was deleted.

37 changes: 0 additions & 37 deletions builtins/logic.go

This file was deleted.

16 changes: 0 additions & 16 deletions builtins/stack_ops.go

This file was deleted.

29 changes: 0 additions & 29 deletions builtins/standard.go

This file was deleted.

83 changes: 83 additions & 0 deletions eval/booleans.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package eval

import (
"github.com/brendantang/naiveconcat/data"
)

// not pops a boolean and pushes its negation.
func not(d *data.Dictionary, s *data.Stack) error {
b, err := s.Pop()
if err != nil {
return err
}
if b.Type != data.Boolean {
return data.TypeError(b, data.Boolean)
}
s.Push(data.NewBoolean(!b.Bool))
return nil
}

// or pops two booleans and pushes TRUE if either of them is TRUE, FALSE
// otherwise.
func or(d *data.Dictionary, s *data.Stack) error {
a, err := s.Pop()
if err != nil {
return err
}
if a.Type != data.Boolean {
return data.TypeError(a, data.Boolean)
}
b, err := s.Pop()
if err != nil {
return err
}
if b.Type != data.Boolean {
return data.TypeError(b, data.Boolean)
}
s.Push(data.NewBoolean(b.Bool || a.Bool))
return nil
}

// and pops two booleans and pushes TRUE if both of them are TRUE, FALSE
// otherwise.
func and(d *data.Dictionary, s *data.Stack) error {
a, err := s.Pop()
if err != nil {
return err
}
if a.Type != data.Boolean {
return data.TypeError(a, data.Boolean)
}
b, err := s.Pop()
if err != nil {
return err
}
if b.Type != data.Boolean {
return data.TypeError(b, data.Boolean)
}
s.Push(data.NewBoolean(b.Bool && a.Bool))
return nil
}

// then pops a predicate and a value. If the predicate is TRUE, push the value.
// Otherwise discard it.
func then(d *data.Dictionary, s *data.Stack) error {
predicate, err := s.Pop()
if err != nil {
return err
}
if predicate.Type != data.Boolean {
return data.TypeError(predicate, data.Boolean)
}
consequent, err := s.Pop()
if err != nil {
return err
}
if predicate.Bool {
err := Eval(consequent, d, s)
if err != nil {
return err
}
}
return nil
}
46 changes: 46 additions & 0 deletions eval/builtins.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package eval

import (
"github.com/brendantang/naiveconcat/data"
)

// StdDict returns a data.Dictionary with bindings for the standard primitive words.
func StdDict() *data.Dictionary {
return data.NewDictionary(
nil,
map[string]data.Value{
// IO
"say": data.NewProc(say), // pop a value and print it
"stack": data.NewProc(showStack), // print the whole stack

// MATH
"+": data.NewProc(add), // pop two numbers and push their sum
"-": data.NewProc(subtract), // pop a, pop b, push b - a
"*": data.NewProc(multiply), // pop two numbers and push their product
"/": data.NewProc(divide), // pop a, pop b, push b divided by a
"=": data.NewProc(equal), // pop two numbers and push whether they're equal

// BOOLEANS
"true": data.NewBoolean(true), // TRUE literal
"false": data.NewBoolean(false), // FALSE literal
"not": data.NewProc(not), // pop a boolean, push its negation
"or": data.NewProc(or), // pop two bools, push a bool saying whether either is true
"and": data.NewProc(and), // pop two bools, push a bool saying whether both are true
"then": data.NewProc(then), // pop a bool and x, evaluate x if the bool is TRUE

// QUOTATIONS
"length": data.NewProc(length), // push length of the quotation on top of the stack
"lop": data.NewProc(lop), // pop quotation { a b c ... }, push { b c ... }, push a

// DICTIONARY MANIPULATION
"let": data.NewProc(let), // pop a string and a value, make a word named by string, defined by value
"define": data.NewProc(define), // pop a string and x. make a word named by string, defined by proc that evals to x.

// STACK MANIPULATION
"dup": data.NewProc(dup), // pop a, push a, push a
"drop": data.NewProc(drop), // pop a, discard it
"apply": data.NewProc(apply), // pop x. if x is a quotation, eval each item. otherwise, eval x.
"lambda": data.NewProc(lambda), // pop x, push a proc that evals to x.
},
)
}
49 changes: 49 additions & 0 deletions eval/dict_manipulation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package eval

import (
"github.com/brendantang/naiveconcat/data"
)

// let pops a string and the next value, then saves a word named for that string
// which evaluates to that value.
func let(d *data.Dictionary, s *data.Stack) error {
wordName, err := s.Pop()
if err != nil {
return err
}
if wordName.Type != data.String {
return data.TypeError(wordName, data.String)
}
definition, err := s.Pop()
if err != nil {
return err
}

d.Set(wordName.Str, definition)
return nil
}

// define pops a string and the next value, then saves a word named for that string which evaluates to a procedure that applies that value.
func define(d *data.Dictionary, s *data.Stack) error {

wordName, err := s.Pop()
if err != nil {
return err
}
if wordName.Type != data.String {
return data.TypeError(wordName, data.String)
}
definition, err := s.Pop()
if err != nil {
return err
}
proc := data.NewProc(
func(d *data.Dictionary, s *data.Stack) error {
s.Push(definition)
return apply(d, s)
},
)
d.Set(wordName.Str, proc)

return nil
}
Loading

0 comments on commit a99b610

Please sign in to comment.