Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add module system #10

Merged
merged 8 commits into from
Aug 6, 2017
Merged
Prev Previous commit
Next Next commit
Remove the explicitly defined parsers for lambda, let, and letrec
Will remove others in a later commit.

These end up not being necessary if the terms are just parsed and tagged in one
of the value parsers. Minor tweaks needed in other files that were expecting the
parsed tree to be shaped slightly differently, but nothing too major.
  • Loading branch information
smpoulsen committed Aug 4, 2017
commit b3255ada011ffadffde9ab668afac57b3d9a4790
2 changes: 1 addition & 1 deletion README.org
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
Additional examples can be found in the [[https://github.com/tpoulsen/terp/tree/master/examples][examples]] directory.
* Usage
** Comments
Comments are single-line and begin with `;;`:
Comments are single-line and begin with =;;=:
#+BEGIN_SRC scheme
;; A comment
(+ 5 1)
Expand Down
35 changes: 19 additions & 16 deletions lib/terp.ex
Original file line number Diff line number Diff line change
Expand Up @@ -99,26 +99,11 @@ defmodule Terp do
:__string ->
str = List.first(children)
str.node
:__lambda ->
Function.lambda(children, env)
:__lambda -> :__lambda
:__quote ->
Enum.map(children, &(&1.node))
:__letrec ->
Function.letrec(tree, env)
:__cond ->
Boolean.cond(children, env)
:__let ->
[name | [bound | []]] = children
eval_expr(name,
fn y ->
fn name ->
if y == name do
eval_expr(bound, env)
else
env.(name)
end
end
end)
:__apply ->
[operator | operands] = children
operator = eval_expr(operator, env)
Expand All @@ -129,6 +114,22 @@ defmodule Terp do
case operator do
:__if ->
Boolean.conditional(operands, env)
:__letrec ->
Function.letrec(operands, env)
:__let ->
[name | [bound | []]] = operands
eval_expr(name,
fn y ->
fn name ->
if y == name do
eval_expr(bound, env)
else
env.(name)
end
end
end)
:__lambda ->
Function.lambda(operands, env)
:+ ->
Arithmetic.add(Enum.map(operands, &eval_expr(&1, env)))
:* ->
Expand Down Expand Up @@ -186,6 +187,8 @@ defmodule Terp do
:__car -> :__car
:__cdr -> :__cdr
:__empty -> :__empty
:__let -> :__let
:__letrec -> :__letrec
x -> env.(x)
end
end
Expand Down
15 changes: 7 additions & 8 deletions lib/terp/function.ex
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,19 @@ defmodule Terp.Function do
120
"""
def y(f) do
#fix = fn (x) ->
#f.(fn (g) -> x.(x).(g) end)
#end
#fix.(fix)
f.(fn x ->
y(f).(x)
end)
end

def letrec(%RoseTree{node: :__letrec, children: children}, env) do
[name | [bound | []]] = children
def letrec([name | [bound | []]], env) do
# Make a new function wrapping bound, replacing the recursive call with a bound variable, :z
recursive_fn = :__lambda
|> RoseTree.new([RoseTree.new(:__quote, [:z]), RoseTree.update_node(bound, name.node, :z)])
recursive_fn = :__apply
|> RoseTree.new([
RoseTree.new(:__lambda),
RoseTree.new(:__quote, [:z]),
RoseTree.update_node(bound, name.node, :z)
])
|> Terp.eval_expr(env)
|> y()

Expand Down
39 changes: 3 additions & 36 deletions lib/terp/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ defmodule Terp.Parser do
comment_parser(),
literal_parser(),
list_parser(),
lambda_parser(),
letrec_parser(),
let_parser(),
cond_parser(),
application_parser(),
ignore(newline()),
Expand All @@ -52,36 +49,6 @@ defmodule Terp.Parser do
map(app_parser, fn x -> {:__apply, x} end)
end

# Parser for a lambda expression.
defp lambda_parser() do
l_parser = between(
string("(lambda"),
valid_expr_parser(),
char(")")
)
map(l_parser, fn x -> {:__lambda, x} end)
end

# Parser for a lambda expression.
defp let_parser() do
l_parser = between(
string("(let"),
valid_expr_parser(),
char(")")
)
map(l_parser, fn x -> {:__let, x} end)
end

# Parser for recursive functions.
defp letrec_parser() do
l_parser = between(
string("(letrec"),
valid_expr_parser(),
char(")")
)
map(l_parser, fn x -> {:__letrec, x} end)
end

# Parse a cond expression: (cond [c r] [c r])
defp cond_parser() do
l_parser = between(
Expand All @@ -108,9 +75,6 @@ defmodule Terp.Parser do
literal_parser(),
list_parser(),
lazy(fn -> cond_parser() end),
lazy(fn -> lambda_parser() end),
lazy(fn -> letrec_parser() end),
lazy(fn -> let_parser() end),
lazy(fn -> application_parser() end),
ignore(space()),
ignore(newline()),
Expand Down Expand Up @@ -172,6 +136,9 @@ defmodule Terp.Parser do
map(string("car"), fn _x -> :__car end),
map(string("cdr"), fn _x -> :__cdr end),
map(string("empty?"), fn _x -> :__empty end),
map(string("lambda"), fn _x -> :__lambda end),
map(string("letrec"), fn _x -> :__letrec end),
map(string("let"), fn _x -> :__let end),
])
end

Expand Down
43 changes: 32 additions & 11 deletions todo.org
Original file line number Diff line number Diff line change
@@ -1,20 +1,41 @@
#+TODO: TODO(t) INPROGRESS(i!) | DONE(d@/!) ICEBOX(x@)

* TODOs
** TODO pattern matching
=pmatch= or equivalent, a list of possible cases and evaluate the first that's true
<2017-08-03 Thu> - Added =cond= for multi-possibility conditionals. Pattern matching still to come.
** TODO clean up parser and terp implementations
There's duplication and stuff that can likely be removed now that more functionality is built out.
Would like to redo some of the early parsers in the style of more recent ones, e.g. tagging the value.
** TODO repl
An elixir shell that just waits for input and runs terp eval on it?
** TODO module system
** TODO variable/defined function hoisting
** TODO prelude
** INPROGRESS [#A] module system
- State "INPROGRESS" from "TODO" [2017-08-04 Fri 10:22]
*** Example syntax:
=module= followed by the module's name and a list of the functions it exports:
#+BEGIN_SRC scheme
(module Prelude.List
'(length
reverse
...])
#+END_SRC

To import:
#+BEGIN_SRC scheme
(import Prelude.List) ;; import all functions from the module

(import Prelude.List
'(length)) ;; import just a given function
#+END_SRC
<2017-08-04 Fri 16:45> Scrapping the above idea and going with something more akin to Racket's module system.
** INPROGRESS [#A] prelude
- State "INPROGRESS" from "TODO" [2017-08-04 Fri 10:22]
Standard library
- [ ] Add new functions
- [ ] map, filter, fold, etc...
- [ ] length, etc...
- [ ] Rewrite some of the built-in functions that are currently in elixir in terp.
** TODO [#A] clean up parser and terp implementations
There's duplication and stuff that can likely be removed now that more functionality is built out.
Would like to redo some of the early parsers in the style of more recent ones, e.g. tagging the value.
** TODO [#B] variable/defined function hoisting
** TODO [#B] pattern matching
=pmatch= or equivalent, a list of possible cases and evaluate the first that's true
<2017-08-03 Thu> - Added =cond= for multi-possibility conditionals. Pattern matching still to come.
** TODO [#C] repl
An elixir shell that just waits for input and runs terp eval on it?
** DONE recursive functions
CLOSED: [2017-08-02 Wed 18:26]
=letrec= to define a recursive function
Expand Down