Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions lisp_interpreter.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ pub(all) enum Value {
} derive(Debug)

///|
pub impl ToJson for Value with to_json(self) {
pub extend Value with @debug.Debug::{to_repr}

///|
pub impl ToJson for Value with fn to_json(self) {
match self {
Number(n) => n.to_json()
Boolean(b) => Json::boolean(b)
Expand All @@ -18,11 +21,17 @@ pub impl ToJson for Value with to_json(self) {
}
}

///|
pub extend Value with ToJson::{to_json}

///|
pub struct Env {
mut inner : @sorted_map.SortedMap[String, Value]
} derive(Debug)

///|
pub extend Env with @debug.Debug::{to_repr}

// ///|
// fn Environment::new() -> Environment {
// {}
Expand All @@ -41,7 +50,7 @@ fn Env::get(self : Env, key : String) -> Value? {

///|
fn Env::fork(self : Env) -> Env {
{ inner: self.inner }
{ inner: self.inner, }
}

///|
Expand All @@ -53,9 +62,12 @@ priv suberror EvalError {
TypeError(String)
} derive(Debug)

///|
extend EvalError with @debug.Debug::{to_repr}

///|
pub fn Env::builtin() -> Self {
let env = { inner: @sorted_map.SortedMap::new() }
let env = { inner: @sorted_map.SortedMap::new(), }
env.set(".", BuiltinFunction("dummy"))
env.set("+", BuiltinFunction("+"))
env.set("-", BuiltinFunction("-"))
Expand Down Expand Up @@ -448,16 +460,22 @@ fn is_truthy(val : Value) -> Bool {
}

///|
pub impl Show for Value with output(self, logger) {
pub impl Show for Value with fn output(self, logger) {
logger.write_string(@debug.render(self.to_repr(), max_depth=2147483647))
}

///|
pub impl Show for Env with output(self, logger) {
pub extend Value with Show::{to_string, output}

///|
pub impl Show for Env with fn output(self, logger) {
logger.write_string(@debug.render(self.to_repr(), max_depth=2147483647))
}

///|
impl Show for EvalError with output(self, logger) {
pub extend Env with Show::{to_string, output}

///|
impl Show for EvalError with fn output(self, logger) {
logger.write_string(@debug.render(self.to_repr(), max_depth=2147483647))
}
3 changes: 2 additions & 1 deletion lisp_interpreter_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ fn eval_string(
let result = @lisp_interpreter.evaluate(sexp)
result.to_json()
} catch {
@builtin.Failure(err) => { "Err": err.split("FAILED:")[1:].to_string() }
@builtin.Failure(err) =>
{ "Err": err.split("FAILED:").drop(1).join("FAILED:").trim().to_owned() }
err => { "Err": err.to_string() }
}
json_inspect(json, content?, loc~, args_loc~)
Expand Down
17 changes: 17 additions & 0 deletions moon.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name = "bobzhang/lisp_interpreter"

version = "0.1.1"

readme = "README.md"

repository = "https://github.com/moonbit-community/lisp_interpreter"

license = "Apache-2.0"

keywords = [ ]

description = ""

options(
"alert-list": "+test_import_all",
)
10 changes: 0 additions & 10 deletions moon.mod.json

This file was deleted.

18 changes: 17 additions & 1 deletion pkg.generated.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,32 @@ pub suberror ParseError {
UnexpectedParens(String)
UnexpectedEOF
} derive(ToJson, @debug.Debug)
pub fn ParseError::output(Self, &Logger) -> Unit
pub fn ParseError::to_json(Self) -> Json
pub fn ParseError::to_repr(Self) -> @debug.Repr
pub fn ParseError::to_string(Self) -> String
pub impl Show for ParseError

// Types and methods
pub struct Env {
mut inner : @sorted_map.SortedMap[String, Value]
} derive(@debug.Debug)
pub fn Env::builtin() -> Self
pub fn Env::output(Self, &Logger) -> Unit
pub fn Env::to_repr(Self) -> @debug.Repr
pub fn Env::to_string(Self) -> String
pub impl Show for Env

pub(all) enum Sexp {
Atom(String)
List(Array[Sexp])
} derive(Eq, ToJson, @debug.Debug)
pub fn Sexp::equal(Self, Self) -> Bool
pub fn Sexp::not_equal(Self, Self) -> Bool
pub fn Sexp::output(Self, &Logger) -> Unit
pub fn Sexp::to_json(Self) -> Json
pub fn Sexp::to_repr(Self) -> @debug.Repr
pub fn Sexp::to_string(Self) -> String
pub impl Show for Sexp

pub(all) enum Value {
Expand All @@ -41,10 +54,13 @@ pub(all) enum Value {
Function(Array[String], Sexp, Env)
BuiltinFunction(String)
} derive(@debug.Debug)
pub fn Value::output(Self, &Logger) -> Unit
pub fn Value::to_json(Self) -> Json
pub fn Value::to_repr(Self) -> @debug.Repr
pub fn Value::to_string(Self) -> String
pub impl Show for Value
pub impl ToJson for Value

// Type aliases

// Traits

40 changes: 32 additions & 8 deletions sexp.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ pub(all) enum Sexp {
List(Array[Sexp])
} derive(Debug, Eq, ToJson)

///|
pub extend Sexp with @debug.Debug::{to_repr}

///|
pub extend Sexp with Eq::{equal, not_equal}

///|
pub extend Sexp with ToJson::{to_json}

///|
/// TODO(upstream):
/// Warning: The type 'ParseError' does not occur in public signature of
Expand All @@ -19,6 +28,12 @@ pub suberror ParseError {
UnexpectedEOF
} derive(Debug, ToJson)

///|
pub extend ParseError with @debug.Debug::{to_repr}

///|
pub extend ParseError with ToJson::{to_json}

///|
priv enum Token {
Lparen
Expand All @@ -27,7 +42,7 @@ priv enum Token {
}

///|
impl ToJson for Token with to_json(self) {
impl ToJson for Token with fn to_json(self) {
match self {
Lparen => "("
RParen => ")"
Expand Down Expand Up @@ -78,7 +93,7 @@ priv struct Lexer {

///|
fn Lexer::new(input : String) -> Lexer {
{ input, pos: 0 }
{ input, pos: 0, }
}

///|
Expand Down Expand Up @@ -164,14 +179,15 @@ fn Lexer::decode_string(self : Lexer) -> Token raise {
test "decode_string" {
fn decode_string(s) {
Ok(Lexer::new(s).decode_string()) catch {
@builtin.Failure(err) => Err(err.split("FAILED:")[1:].to_string()) // FIXME: upstream
@builtin.Failure(err) =>
Err(err.split("FAILED:").drop(1).join("FAILED:").trim().to_owned()) // FIXME: upstream
err => Err(err.to_string())
}
}

json_inspect(decode_string("\"hello\""), content={ "Ok": "\"hello\"" })
json_inspect(decode_string("\"hello\n\""), content={
"Err": "[\" unexpected newline in string\"]",
"Err": "unexpected newline in string",
})
json_inspect(
decode_string(
Expand Down Expand Up @@ -263,7 +279,8 @@ test "decode_atom" {
test "decode" {
fn tokenize(s) {
Ok(Lexer::new(s).decode()) catch {
@builtin.Failure(err) => Err(err.split("FAILED:")[1:].to_string()) // FIXME: upstream
@builtin.Failure(err) =>
Err(err.split("FAILED:").drop(1).join("FAILED:").trim().to_owned()) // FIXME: upstream
err => Err(err.to_string())
}
}
Expand Down Expand Up @@ -297,7 +314,8 @@ test "decode" {
test {
fn tokenize(s) {
Ok(Lexer::new(s).decode()) catch {
@builtin.Failure(err) => Err(err.split("FAILED:")[1:].to_string()) // FIXME: upstream
@builtin.Failure(err) =>
Err(err.split("FAILED:").drop(1).join("FAILED:").trim().to_owned()) // FIXME: upstream
err => Err(err.to_string())
}
}
Expand Down Expand Up @@ -354,11 +372,17 @@ test "tokenize unicode emoji" {
// }

///|
pub impl Show for Sexp with output(self, logger) {
pub impl Show for Sexp with fn output(self, logger) {
logger.write_string(@debug.render(self.to_repr(), max_depth=2147483647))
}

///|
pub impl Show for ParseError with output(self, logger) {
pub extend Sexp with Show::{to_string, output}

///|
pub impl Show for ParseError with fn output(self, logger) {
logger.write_string(@debug.render(self.to_repr(), max_depth=2147483647))
}

///|
pub extend ParseError with Show::{to_string, output}
52 changes: 37 additions & 15 deletions sexp_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,29 @@
///|
test "parse extra tokens" {
let input = "(hello) world"
json_inspect(try? @lisp_interpreter.parse_sexp(input), content={
"Err": ["UnmatchedParens", "unexpected tokens at the end"],
})
try @lisp_interpreter.parse_sexp(input) catch {
@lisp_interpreter.UnmatchedParens(_) as err =>
json_inspect(err, content=[
"UnmatchedParens", "unexpected tokens at the end",
])
err => fail("unexpected error: \{err}")
} noraise {
_ => fail("expected parse_sexp to raise")
}
}

///|
test "parse unexpected closing paren" {
let input = ")hello"
json_inspect(try? @lisp_interpreter.parse_sexp(input), content={
"Err": ["UnexpectedParens", "unexpected closing parenthesis"],
})
try @lisp_interpreter.parse_sexp(input) catch {
@lisp_interpreter.UnexpectedParens(_) as err =>
json_inspect(err, content=[
"UnexpectedParens", "unexpected closing parenthesis",
])
err => fail("unexpected error: \{err}")
} noraise {
_ => fail("expected parse_sexp to raise")
}
}

///|
Expand All @@ -40,20 +52,30 @@ test "parse nested" {
///|
test "parse error" {
let input = "(hello (world"
inspect(
try? @lisp_interpreter.parse_sexp(input),
content=(
#|Err(UnmatchedParens("missing closing parenthesis"))
),
)
try @lisp_interpreter.parse_sexp(input) catch {
@lisp_interpreter.UnmatchedParens(_) as err =>
inspect(
err,
content=(
#|UnmatchedParens("missing closing parenthesis")
),
)
err => fail("unexpected error: \{err}")
} noraise {
_ => fail("expected parse_sexp to raise")
}
}

///|
test "parse empty" {
let input = ""
json_inspect(try? @lisp_interpreter.parse_sexp(input), content={
"Err": "UnexpectedEOF",
})
try @lisp_interpreter.parse_sexp(input) catch {
@lisp_interpreter.UnexpectedEOF as err =>
json_inspect(err, content="UnexpectedEOF")
err => fail("unexpected error: \{err}")
} noraise {
_ => fail("expected parse_sexp to raise")
}
}

///|
Expand Down
Loading