labels and mutable variables
This commit is contained in:
parent
a16571acf2
commit
4f13870182
12 changed files with 178 additions and 47 deletions
|
|
@ -34,6 +34,7 @@ pub fn stmt_expr(expr: Expr) -> Statement {
|
||||||
|
|
||||||
pub fn define_expr(name: &str, expr: Expr) -> Definition {
|
pub fn define_expr(name: &str, expr: Expr) -> Definition {
|
||||||
Definition {
|
Definition {
|
||||||
|
mutable: false,
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
expr,
|
expr,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ pub enum Statement {
|
||||||
|
|
||||||
#[derive(PartialEq, PartialOrd, Debug, Clone)]
|
#[derive(PartialEq, PartialOrd, Debug, Clone)]
|
||||||
pub struct Definition {
|
pub struct Definition {
|
||||||
|
pub mutable: bool,
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
pub expr: Expr,
|
pub expr: Expr,
|
||||||
}
|
}
|
||||||
|
|
@ -65,9 +66,15 @@ pub enum Value {
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Record(Record),
|
Record(Record),
|
||||||
Vector(Vector),
|
Vector(Vector),
|
||||||
|
Label(Label),
|
||||||
|
Ref(Ref),
|
||||||
Closure { env: EnvName, expr: Box<Expr> },
|
Closure { env: EnvName, expr: Box<Expr> },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A mutable variable.
|
||||||
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone)]
|
||||||
|
pub struct Ref(pub u64);
|
||||||
|
|
||||||
/// An anonymous function.
|
/// An anonymous function.
|
||||||
#[derive(PartialEq, PartialOrd, Debug, Clone)]
|
#[derive(PartialEq, PartialOrd, Debug, Clone)]
|
||||||
pub struct Fn {
|
pub struct Fn {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ pub fn run(
|
||||||
let env_name = ast::EnvName("global".to_string());
|
let env_name = ast::EnvName("global".to_string());
|
||||||
let mut state = State::new("global".into());
|
let mut state = State::new("global".into());
|
||||||
|
|
||||||
defs_to_env(program.0, &env_name, &mut state.envs)?;
|
defs_to_env(program.0, &env_name, &mut state)?;
|
||||||
|
|
||||||
let main = ast::Expr::Value(state.envs.get(&env_name)?.get(&func)?.clone());
|
let main = ast::Expr::Value(state.envs.get(&env_name)?.get(&func)?.clone());
|
||||||
|
|
||||||
|
|
@ -39,8 +39,16 @@ fn eval_statement(
|
||||||
) -> Result<StatementResult, Error> {
|
) -> Result<StatementResult, Error> {
|
||||||
match statement {
|
match statement {
|
||||||
ast::Statement::Expr(expr) => eval_expr(expr_env, state, expr).map(StatementResult::Result),
|
ast::Statement::Expr(expr) => eval_expr(expr_env, state, expr).map(StatementResult::Result),
|
||||||
ast::Statement::Let(ast::Definition { name, expr }) => {
|
ast::Statement::Let(ast::Definition {
|
||||||
let result = eval_expr(expr_env, state, expr)?;
|
mutable,
|
||||||
|
name,
|
||||||
|
expr,
|
||||||
|
}) => {
|
||||||
|
let mut result = eval_expr(expr_env, state, expr)?;
|
||||||
|
if *mutable {
|
||||||
|
let reference = state.insert_variable(result);
|
||||||
|
result = ast::Value::Ref(reference);
|
||||||
|
}
|
||||||
expr_env.insert(name.clone(), result.clone());
|
expr_env.insert(name.clone(), result.clone());
|
||||||
Ok(StatementResult::Result(result))
|
Ok(StatementResult::Result(result))
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +150,19 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result<ast:
|
||||||
.insert(name.clone(), rhs);
|
.insert(name.clone(), rhs);
|
||||||
eval_expr(expr_env, state, &ast::UNIT)
|
eval_expr(expr_env, state, &ast::UNIT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// access via labels
|
// access via labels
|
||||||
|
ast::Expr::Access { expr, field } => {
|
||||||
|
let rhs = eval_expr(expr_env, state, rhs)?;
|
||||||
|
if let Some(mut nested_field) =
|
||||||
|
access_nested_field(expr_env, state, expr, field)?
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
|
} else {
|
||||||
|
todo!() // error nested field unreachable
|
||||||
|
}
|
||||||
|
} */
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -153,17 +173,45 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result<ast:
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
fn access_nested_field<'a>(
|
||||||
|
expr_env_name: &Env,
|
||||||
|
state: &'a mut State,
|
||||||
|
expr: &ast::Expr,
|
||||||
|
label: &ast::Label,
|
||||||
|
) -> Result<&'a mut ast::Value, Error> {
|
||||||
|
//let lhs = eval_expr(expr_env, state, expr)?;
|
||||||
|
match expr {
|
||||||
|
ast::Expr::Var(var) => {
|
||||||
|
if let Some(mut value) = state.envs.get(&expr_env.name)?.get(&var)? {
|
||||||
|
match &value {
|
||||||
|
&ast::Value::Record(record) => {
|
||||||
|
record.
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
fn defs_to_env(
|
fn defs_to_env(
|
||||||
defs: Vec<ast::Definition>,
|
defs: Vec<ast::Definition>,
|
||||||
env_name: &ast::EnvName,
|
env_name: &ast::EnvName,
|
||||||
envs: &mut Envs,
|
state: &mut State,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut env = Env::new(env_name.clone());
|
let mut env = Env::new(env_name.clone());
|
||||||
|
|
||||||
for def in defs {
|
for def in defs {
|
||||||
let (name, closure) = match def {
|
let (mutable, name, closure) = match def {
|
||||||
ast::Definition { expr, name } => (
|
ast::Definition {
|
||||||
|
mutable,
|
||||||
|
expr,
|
||||||
|
name,
|
||||||
|
} => (
|
||||||
|
mutable,
|
||||||
name,
|
name,
|
||||||
ast::Value::Closure {
|
ast::Value::Closure {
|
||||||
expr: Box::new(expr.clone()),
|
expr: Box::new(expr.clone()),
|
||||||
|
|
@ -171,10 +219,15 @@ fn defs_to_env(
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
if mutable {
|
||||||
|
let reference = state.insert_variable(closure);
|
||||||
|
env.insert_nodup(&name, ast::Value::Ref(reference))?;
|
||||||
|
} else {
|
||||||
env.insert_nodup(&name, closure)?;
|
env.insert_nodup(&name, closure)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
envs.0.insert(env_name.clone(), env);
|
state.envs.0.insert(env_name.clone(), env);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use crate::ast;
|
use crate::ast;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, thiserror::Error)]
|
#[derive(PartialEq, Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
|
@ -51,23 +52,35 @@ impl Namer {
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
namer: Namer,
|
env_namer: Namer,
|
||||||
pub envs: Envs,
|
pub envs: Envs,
|
||||||
|
variable_namer: Namer,
|
||||||
|
pub variables: Variables,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Variables(pub HashMap<ast::Ref, ast::Value>);
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn new(name: String) -> State {
|
pub fn new(name: String) -> State {
|
||||||
State {
|
State {
|
||||||
name,
|
name,
|
||||||
namer: Namer::new(),
|
env_namer: Namer::new(),
|
||||||
envs: Envs(BTreeMap::new()),
|
envs: Envs(BTreeMap::new()),
|
||||||
|
variable_namer: Namer::new(),
|
||||||
|
variables: Variables(HashMap::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn generate_env(&mut self, env: Env) -> Result<ast::EnvName, Error> {
|
pub fn generate_env(&mut self, env: Env) -> Result<ast::EnvName, Error> {
|
||||||
let env_name = ast::EnvName(format!("{}_{}", self.name, self.namer.next()));
|
let env_name = ast::EnvName(format!("{}_{}", self.name, self.env_namer.next()));
|
||||||
self.envs.insert(&env_name, env)?;
|
self.envs.insert(&env_name, env)?;
|
||||||
Ok(env_name)
|
Ok(env_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert_variable(&mut self, value: ast::Value) -> ast::Ref {
|
||||||
|
let name = ast::Ref(self.variable_namer.next());
|
||||||
|
self.variables.0.insert(name.clone(), value);
|
||||||
|
name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -45,20 +45,13 @@ fn parse_set(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_dot(tokens: &mut Tokens, expr: ast::Expr) -> Result<ast::Expr, Error> {
|
fn parse_dot(tokens: &mut Tokens, expr: ast::Expr) -> Result<ast::Expr, Error> {
|
||||||
if let Some(_dot) = tokens.next_if(&Token::Dot) {
|
if let Some(labels) = tokens.many(parse_label)? {
|
||||||
if let Some(labels) = tokens.many_sep_by(&Token::Dot, parse_identifier_label)? {
|
|
||||||
Ok(labels
|
Ok(labels
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.fold(expr, |acc, label| ast::Expr::Access {
|
.fold(expr, |acc, label| ast::Expr::Access {
|
||||||
expr: Box::new(acc),
|
expr: Box::new(acc),
|
||||||
field: label,
|
field: label,
|
||||||
}))
|
}))
|
||||||
} else {
|
|
||||||
Err(Error::UnexpectedToken {
|
|
||||||
expected: Token::Dot,
|
|
||||||
got: tokens.next(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
@ -66,9 +59,17 @@ fn parse_dot(tokens: &mut Tokens, expr: ast::Expr) -> Result<ast::Expr, Error> {
|
||||||
|
|
||||||
fn parse_definition(tokens: &mut Tokens) -> ParseResult<ast::Definition> {
|
fn parse_definition(tokens: &mut Tokens) -> ParseResult<ast::Definition> {
|
||||||
if let Some(_) = tokens.next_if(&Token::Let) {
|
if let Some(_) = tokens.next_if(&Token::Let) {
|
||||||
|
let mutable = match tokens.next_if(&Token::Mut) {
|
||||||
|
Some(_) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
if let Some(name) = parse_identifier_name(tokens)? {
|
if let Some(name) = parse_identifier_name(tokens)? {
|
||||||
if let Some(expr) = parse_set(tokens)? {
|
if let Some(expr) = parse_set(tokens)? {
|
||||||
Ok(Some(ast::Definition { name, expr }))
|
Ok(Some(ast::Definition {
|
||||||
|
mutable,
|
||||||
|
name,
|
||||||
|
expr,
|
||||||
|
}))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::UnexpectedToken {
|
Err(Error::UnexpectedToken {
|
||||||
expected: Token::Equals,
|
expected: Token::Equals,
|
||||||
|
|
@ -220,7 +221,7 @@ fn parse_vector(tokens: &mut Tokens) -> ParseResult<ast::Expr> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_record_field_expr(tokens: &mut Tokens) -> ParseResult<(ast::Label, ast::Expr)> {
|
fn parse_record_field_expr(tokens: &mut Tokens) -> ParseResult<(ast::Label, ast::Expr)> {
|
||||||
if let Some(label) = parse_identifier_label(tokens)? {
|
if let Some(label) = parse_label(tokens)? {
|
||||||
if let Some(_) = tokens.next_if(&Token::Colon) {
|
if let Some(_) = tokens.next_if(&Token::Colon) {
|
||||||
if let Some(expr) = parse_expr(tokens)? {
|
if let Some(expr) = parse_expr(tokens)? {
|
||||||
Ok(Some((label, expr)))
|
Ok(Some((label, expr)))
|
||||||
|
|
@ -277,8 +278,16 @@ fn parse_identifier_name(tokens: &mut Tokens) -> ParseResult<ast::Name> {
|
||||||
Ok(parse_identifier_string(tokens)?.map(|string| ast::Name(string)))
|
Ok(parse_identifier_string(tokens)?.map(|string| ast::Name(string)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_identifier_label(tokens: &mut Tokens) -> ParseResult<ast::Label> {
|
fn parse_label(tokens: &mut Tokens) -> ParseResult<ast::Label> {
|
||||||
Ok(parse_identifier_string(tokens)?.map(|string| ast::Label(string)))
|
if let Some(LocatedToken {
|
||||||
|
token: Token::Label(string),
|
||||||
|
..
|
||||||
|
}) = tokens.next_if(&Token::Label("".into()))
|
||||||
|
{
|
||||||
|
Ok(Some(ast::Label(string)))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_identifier_string(tokens: &mut Tokens) -> ParseResult<String> {
|
fn parse_identifier_string(tokens: &mut Tokens) -> ParseResult<String> {
|
||||||
|
|
@ -335,7 +344,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn record() {
|
fn record() {
|
||||||
let program = "{ hello: 17, hi: \"cool\"}".to_string();
|
let program = "{ .hello: 17, .hi: \"cool\"}".to_string();
|
||||||
let result = parse(&mut scan(program), parse_expr);
|
let result = parse(&mut scan(program), parse_expr);
|
||||||
insta::assert_debug_snapshot!(result);
|
insta::assert_debug_snapshot!(result);
|
||||||
}
|
}
|
||||||
|
|
@ -353,7 +362,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn assign() {
|
fn assign() {
|
||||||
let program = "x = [2, { hello: 7 }];".to_string();
|
let program = "x = [2, { .hello: 7 }];".to_string();
|
||||||
let result = parse(&mut scan(program), parse_expr);
|
let result = parse(&mut scan(program), parse_expr);
|
||||||
insta::assert_debug_snapshot!(result);
|
insta::assert_debug_snapshot!(result);
|
||||||
}
|
}
|
||||||
|
|
@ -382,11 +391,17 @@ mod tests {
|
||||||
insta::assert_debug_snapshot!(result);
|
insta::assert_debug_snapshot!(result);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
|
fn let_mut_number() {
|
||||||
|
let program = "let mut x = 108;".to_string();
|
||||||
|
let result = parse(&mut scan(program), parse_definition);
|
||||||
|
insta::assert_debug_snapshot!(result);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
fn full_program() {
|
fn full_program() {
|
||||||
let program = "
|
let program = "
|
||||||
let init = fn() {
|
let init = fn() {
|
||||||
return {
|
return {
|
||||||
player: { position: { x: 10, y: 20 }, },
|
.player: { .position: { .x: 10, .y: 20 }, },
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -399,7 +414,7 @@ let draw = fn(frame, state) {
|
||||||
};
|
};
|
||||||
|
|
||||||
let migrate = fn(state) {
|
let migrate = fn(state) {
|
||||||
return { player: { pos: state.player.position } };
|
return { .player: { .pos: state.player.position } };
|
||||||
};
|
};
|
||||||
"
|
"
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,6 @@ pub fn scan(source: String) -> Tokens {
|
||||||
let start = scanner.cursor();
|
let start = scanner.cursor();
|
||||||
if let Some(c) = scanner.pop() {
|
if let Some(c) = scanner.pop() {
|
||||||
match *c {
|
match *c {
|
||||||
'.' => tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: Token::Dot,
|
|
||||||
}),
|
|
||||||
',' => tokens.push(LocatedToken {
|
',' => tokens.push(LocatedToken {
|
||||||
start,
|
start,
|
||||||
end: scanner.cursor(),
|
end: scanner.cursor(),
|
||||||
|
|
@ -66,6 +61,31 @@ pub fn scan(source: String) -> Tokens {
|
||||||
end: scanner.cursor(),
|
end: scanner.cursor(),
|
||||||
token: Token::Equals,
|
token: Token::Equals,
|
||||||
}),
|
}),
|
||||||
|
// labels
|
||||||
|
'.' => {
|
||||||
|
let mut str = "".to_string();
|
||||||
|
loop {
|
||||||
|
if let Some(ch) = scanner.peek()
|
||||||
|
&& !ch.is_alphanumeric()
|
||||||
|
&& *ch != '_'
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some(ch) = scanner.pop() {
|
||||||
|
str.push(*ch);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: match str.as_str() {
|
||||||
|
_ => Token::Label(str),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
// comments
|
// comments
|
||||||
'#' => {
|
'#' => {
|
||||||
let mut str = "".to_string();
|
let mut str = "".to_string();
|
||||||
|
|
@ -91,6 +111,7 @@ pub fn scan(source: String) -> Tokens {
|
||||||
token: Token::String(str),
|
token: Token::String(str),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// whitespace
|
||||||
_ if c.is_whitespace() => {}
|
_ if c.is_whitespace() => {}
|
||||||
// numbers
|
// numbers
|
||||||
_ if c.is_numeric() => {
|
_ if c.is_numeric() => {
|
||||||
|
|
@ -137,6 +158,7 @@ pub fn scan(source: String) -> Tokens {
|
||||||
token: match str.as_str() {
|
token: match str.as_str() {
|
||||||
"fn" => Token::Fn,
|
"fn" => Token::Fn,
|
||||||
"let" => Token::Let,
|
"let" => Token::Let,
|
||||||
|
"mut" => Token::Mut,
|
||||||
"return" => Token::Return,
|
"return" => Token::Return,
|
||||||
"true" => Token::True,
|
"true" => Token::True,
|
||||||
"false" => Token::False,
|
"false" => Token::False,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ expression: result
|
||||||
Ok(
|
Ok(
|
||||||
[
|
[
|
||||||
Definition {
|
Definition {
|
||||||
|
mutable: false,
|
||||||
name: Name(
|
name: Name(
|
||||||
"init",
|
"init",
|
||||||
),
|
),
|
||||||
|
|
@ -65,6 +66,7 @@ Ok(
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
Definition {
|
Definition {
|
||||||
|
mutable: false,
|
||||||
name: Name(
|
name: Name(
|
||||||
"update",
|
"update",
|
||||||
),
|
),
|
||||||
|
|
@ -99,6 +101,7 @@ Ok(
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
Definition {
|
Definition {
|
||||||
|
mutable: false,
|
||||||
name: Name(
|
name: Name(
|
||||||
"draw",
|
"draw",
|
||||||
),
|
),
|
||||||
|
|
@ -155,6 +158,7 @@ Ok(
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
Definition {
|
Definition {
|
||||||
|
mutable: false,
|
||||||
name: Name(
|
name: Name(
|
||||||
"migrate",
|
"migrate",
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
source: src/parser/parser.rs
|
||||||
|
expression: result
|
||||||
|
---
|
||||||
|
Ok(
|
||||||
|
Definition {
|
||||||
|
mutable: true,
|
||||||
|
name: Name(
|
||||||
|
"x",
|
||||||
|
),
|
||||||
|
expr: Value(
|
||||||
|
Int(
|
||||||
|
108,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
@ -4,6 +4,7 @@ expression: result
|
||||||
---
|
---
|
||||||
Ok(
|
Ok(
|
||||||
Definition {
|
Definition {
|
||||||
|
mutable: false,
|
||||||
name: Name(
|
name: Name(
|
||||||
"x",
|
"x",
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,7 @@ expression: result
|
||||||
Identifier(
|
Identifier(
|
||||||
"console",
|
"console",
|
||||||
),
|
),
|
||||||
Dot,
|
Label(
|
||||||
Identifier(
|
|
||||||
"log",
|
"log",
|
||||||
),
|
),
|
||||||
OpenParen,
|
OpenParen,
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,7 @@ expression: result
|
||||||
Identifier(
|
Identifier(
|
||||||
"frame",
|
"frame",
|
||||||
),
|
),
|
||||||
Dot,
|
Label(
|
||||||
Identifier(
|
|
||||||
"clear",
|
"clear",
|
||||||
),
|
),
|
||||||
OpenParen,
|
OpenParen,
|
||||||
|
|
@ -134,12 +133,10 @@ expression: result
|
||||||
Identifier(
|
Identifier(
|
||||||
"state",
|
"state",
|
||||||
),
|
),
|
||||||
Dot,
|
Label(
|
||||||
Identifier(
|
|
||||||
"player",
|
"player",
|
||||||
),
|
),
|
||||||
Dot,
|
Label(
|
||||||
Identifier(
|
|
||||||
"position",
|
"position",
|
||||||
),
|
),
|
||||||
CloseCurly,
|
CloseCurly,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ pub struct LocatedToken {
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
Let,
|
Let,
|
||||||
Fn,
|
Fn,
|
||||||
|
Mut,
|
||||||
Return,
|
Return,
|
||||||
Equals,
|
Equals,
|
||||||
OpenParen,
|
OpenParen,
|
||||||
|
|
@ -17,7 +18,6 @@ pub enum Token {
|
||||||
CloseBracket,
|
CloseBracket,
|
||||||
OpenCurly,
|
OpenCurly,
|
||||||
CloseCurly,
|
CloseCurly,
|
||||||
Dot,
|
|
||||||
Comma,
|
Comma,
|
||||||
Semicolon,
|
Semicolon,
|
||||||
Colon,
|
Colon,
|
||||||
|
|
@ -26,6 +26,7 @@ pub enum Token {
|
||||||
Number(u32),
|
Number(u32),
|
||||||
String(String),
|
String(String),
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
|
Label(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
|
@ -52,6 +53,7 @@ impl Tokens {
|
||||||
(Token::Identifier(_), Token::Identifier(_)) => true,
|
(Token::Identifier(_), Token::Identifier(_)) => true,
|
||||||
(Token::Number(_), Token::Number(_)) => true,
|
(Token::Number(_), Token::Number(_)) => true,
|
||||||
(Token::String(_), Token::String(_)) => true,
|
(Token::String(_), Token::String(_)) => true,
|
||||||
|
(Token::Label(_), Token::Label(_)) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue