Skip to content

Commit

Permalink
feat: null constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
viddrobnic committed Jun 17, 2024
1 parent 4b13104 commit 2e67b44
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 16 deletions.
15 changes: 14 additions & 1 deletion examples/overview.aoc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ false
'a'
"foo"[0] // 'f'


// We have two composite data types, that we will take a look at later
// First, variables:
foo = 42
Expand Down Expand Up @@ -151,7 +152,19 @@ rec_sum = fn(n) {
}
print(rec_sum(10)) // 55

// Now let's do a speedrun through the builtin functions:
// We also have a billion dollar mistake: nulls. Nulls have two usages in AoC lang:
// - most of the things are expressions and return some value. Some things are not expressions and return null.
// for instance:
// if (false) {10} // null, because the else statement is empty
// - AoC lang doesn't have error handling and things that would return an error in other languages, return
// null here. For instance int("asdf") or array[-42]. We can also construct null with:
null

// We can check if something is null with builtin function is_null:
is_null(null) // true
is_null(false) // false

// Now that the builtin functions were mentioned, let's do a speed run through them:
len([1, 2]) // 2
len({1: 2}) // 1
len("foo") // 3
Expand Down
2 changes: 2 additions & 0 deletions parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct Node {

#[derive(Debug, PartialEq, Clone)]
pub enum NodeValue {
Null,
Identifier(String),
IntegerLiteral(i64),
FloatLiteral(f64),
Expand Down Expand Up @@ -225,6 +226,7 @@ impl Display for Node {
impl Display for NodeValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NodeValue::Null => write!(f, "null"),
NodeValue::Identifier(ident) => write!(f, "{ident}"),
NodeValue::IntegerLiteral(int) => write!(f, "{int}"),
NodeValue::FloatLiteral(float) => write!(f, "{float}"),
Expand Down
36 changes: 21 additions & 15 deletions parser/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,16 @@ mod test {
},
},
),
(
"'🚗'",
Error {
kind: ErrorKind::NonAsciiChar('🚗'),
range: Range {
start: Position::new(0, 0),
end: Position::new(0, 6),
},
},
),
];

for (input, expected) in tests {
Expand All @@ -472,6 +482,7 @@ mod test {
// line comment
false //inline comment
'A'
null
"#;

let lexer = Lexer::new(input);
Expand Down Expand Up @@ -721,6 +732,14 @@ mod test {
start: Position::new(10, 15),
end: Position::new(11, 0),
},
Range {
start: Position::new(11, 12),
end: Position::new(11, 16),
},
Range {
start: Position::new(11, 16),
end: Position::new(12, 0)
}
]
);

Expand Down Expand Up @@ -786,22 +805,9 @@ mod test {
TokenKind::Eol,
TokenKind::Char(b'A'),
TokenKind::Eol,
TokenKind::Null,
TokenKind::Eol,
]
);
}

#[test]
fn non_ascii_char() {
let mut lexer = Lexer::new("'🚗'");
assert_eq!(
lexer.next(),
Some(Err(Error {
kind: ErrorKind::NonAsciiChar('🚗'),
range: Range {
start: Position::new(0, 0),
end: Position::new(0, 6),
}
}))
);
}
}
1 change: 1 addition & 0 deletions parser/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ impl Parser<'_> {
} = start_token;

let (node_value, end) = match tkn_kind {
TokenKind::Null => (ast::NodeValue::Null, range.end),
TokenKind::Ident(ident) => (ast::NodeValue::Identifier(ident), range.end),
TokenKind::Integer(int) => (ast::NodeValue::IntegerLiteral(int), range.end),
TokenKind::Float(flt) => (ast::NodeValue::FloatLiteral(flt), range.end),
Expand Down
8 changes: 8 additions & 0 deletions parser/src/parser/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fn simple_prefix_expression() -> Result<()> {
break
continue
'~'
null
"#;

let program = parse(input)?;
Expand Down Expand Up @@ -95,6 +96,13 @@ fn simple_prefix_expression() -> Result<()> {
end: Position::new(9, 11),
}
},
ast::Node {
value: ast::NodeValue::Null,
range: Range {
start: Position::new(10, 8),
end: Position::new(10, 12)
}
},
]
);

Expand Down
3 changes: 3 additions & 0 deletions parser/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub enum TokenKind {
Return,
Fn,
Use,
Null,
Eol, // \n
Comment(String),
}
Expand All @@ -63,6 +64,7 @@ impl TokenKind {
"return" => Self::Return,
"fn" => Self::Fn,
"use" => Self::Use,
"null" => Self::Null,
_ => return None,
};

Expand Down Expand Up @@ -143,6 +145,7 @@ impl Display for TokenKind {
TokenKind::Return => write!(f, "RETURN"),
TokenKind::Fn => write!(f, "FN"),
TokenKind::Use => write!(f, "USE"),
TokenKind::Null => write!(f, "NULL"),
TokenKind::Eol => write!(f, "EOL"),
TokenKind::Comment(_) => write!(f, "COMMENT"),
}
Expand Down
1 change: 1 addition & 0 deletions runtime/src/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ impl Compiler {
fn compile_node(&mut self, node: &ast::Node) -> Result<(), Error> {
match &node.value {
ast::NodeValue::Identifier(ident) => self.compile_ident(ident, node.range)?,
ast::NodeValue::Null => self.compile_constant(Object::Null, node.range),
ast::NodeValue::IntegerLiteral(int) => {
self.compile_constant(Object::Integer(*int), node.range);
}
Expand Down
2 changes: 2 additions & 0 deletions runtime/src/vm/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -634,10 +634,12 @@ fn builtin() {
("bool(0)", Ok(Object::Boolean(true))),
("bool(\"false\")", Ok(Object::Boolean(true))),
("bool(int(\"\"))", Ok(Object::Boolean(false))),
("bool(null)", Ok(Object::Boolean(false))),
// IsNull
("is_null(0)", Ok(Object::Boolean(false))),
("is_null(false)", Ok(Object::Boolean(false))),
("is_null(int(\"a\"))", Ok(Object::Boolean(true))),
("is_null(null)", Ok(Object::Boolean(true))),
];

for (input, expected) in tests {
Expand Down

0 comments on commit 2e67b44

Please sign in to comment.