diff --git a/core/src/compiler.rs b/core/src/compiler.rs index cf87564a..5b379794 100644 --- a/core/src/compiler.rs +++ b/core/src/compiler.rs @@ -6,6 +6,7 @@ use std::fmt::Write; use std::iter::{Iterator, Peekable}; +use crate::env::LuaVersion; use crate::{ env::{ContinueMode, Options}, format_clue, @@ -102,7 +103,8 @@ impl<'a> Compiler<'a> { args: FunctionArgs, code: CodeBlock, ) -> Result<(String, String), String> { - let mut code = self.compile_code_block(scope + self.options.env_debug as usize, "", code)?; + let mut code = + self.compile_code_block(scope + self.options.env_debug as usize, "", code)?; let args = self.compile_list(args, ", ", &mut |(arg, default)| { if let Some((default, line)) = default { let default = self.compile_expression(scope + 2, default)?; @@ -357,6 +359,7 @@ impl<'a> Compiler<'a> { SYMBOL(lexeme) => lexeme, VARIABLE { local, + r#const, names, values, line, @@ -387,14 +390,28 @@ impl<'a> Compiler<'a> { result } else { let end = self.indentate_if(ctokens, scope); - let pre = if local { "local " } else { "" }; + let post = if r#const + && self + .options + .env_target + .is_some_and(|lua| lua == LuaVersion::Lua54) + { + " " + } else { + "" + }; + let pre = if local || !post.is_empty() { + "local " + } else { + "" + }; if values.is_empty() { let ident = self.compile_identifiers(names)?; format_clue!(debug, pre, ident, ";", line, end) } else { let values = self.compile_expressions(scope, values)?; let names = self.compile_identifiers(names)?; - format_clue!(debug, pre, names, " = ", values, ";", line, end) + format_clue!(debug, pre, names, post, " = ", values, ";", line, end) } } } @@ -489,23 +506,23 @@ impl<'a> Compiler<'a> { let expr = self.compile_expression(scope, expr)?; Ok(format_clue!("(", name, " == ", expr, ") ")) })?; - format_clue!("if ", if let Some(extraif) = extraif { - condition.pop(); - let extraif = self.compile_expression(scope, extraif)?; - if empty { - extraif + " " + format_clue!( + "if ", + if let Some(extraif) = extraif { + condition.pop(); + let extraif = self.compile_expression(scope, extraif)?; + if empty { + extraif + " " + } else { + format_clue!("(", condition, ") and ", extraif, " ") + } } else { - format_clue!("(", condition, ") and ", extraif, " ") - } - } else { - condition - }, "then") - }; - let end = if i >= last { - "end" - } else { - "else" + condition + }, + "then" + ) }; + let end = if i >= last { "end" } else { "else" }; let pre = self.indentate(scope + i); let internal_code = if internal_expr.is_empty() { None @@ -513,48 +530,23 @@ impl<'a> Compiler<'a> { Some(self.compile_tokens(scope + i, internal_expr)?) }; let code = if i == 0 { - let code = self.compile_code_block( - scope, - &condition, - code, - )? + end; + let code = self.compile_code_block(scope, &condition, code)? + end; if let Some(internal_code) = internal_code { - format_clue!( - internal_code, - '\n', - pre, - code - ) + format_clue!(internal_code, '\n', pre, code) } else { code } } else if default { - self.compile_code_block( - scope + i - 1, - "", - code, - )? + end + self.compile_code_block(scope + i - 1, "", code)? + end } else { - let code = self.compile_code_block( - scope + i, - &condition, - code, - )?; - let mut code = format_clue!( - '\n', - pre, - code, - end - ); + let code = self.compile_code_block(scope + i, &condition, code)?; + let mut code = format_clue!('\n', pre, code, end); if let Some(internal_code) = internal_code { - code = format_clue!( - '\n', - internal_code, - code - ) + code = format_clue!('\n', internal_code, code) } if i >= last { - code += &format_clue!('\n', self.indentate(scope + i - 1), "end"); + code += + &format_clue!('\n', self.indentate(scope + i - 1), "end"); } code }; @@ -575,7 +567,11 @@ impl<'a> Compiler<'a> { debug, "local ", name, " = ", value, ';', line, '\n', branches, end ) } - WHILE_LOOP { condition, code, line } => { + WHILE_LOOP { + condition, + code, + line, + } => { let condition = self.compile_expression(scope, condition)?; let debug = self.compile_debug_line(line, scope, true); let code = self.compile_code_block(scope, "do", code)?; @@ -590,7 +586,11 @@ impl<'a> Compiler<'a> { self.indentate_if(ctokens, scope) ) } - LOOP_UNTIL { condition, code, line } => { + LOOP_UNTIL { + condition, + code, + line, + } => { let condition = self.compile_expression(scope, condition)?; let debug = self.compile_debug_line(line, scope, true); let code = self.compile_code_block(scope, "", code)?; @@ -618,20 +618,8 @@ impl<'a> Compiler<'a> { let code = self.compile_code_block(scope, "do", code)?; let end = self.indentate_if(ctokens, scope); format_clue!( - debug, - "for ", - iterator, - " = ", - start, - ", ", - endexpr, - ", ", - alter, - " ", - code, - debug, - "end", - end + debug, "for ", iterator, " = ", start, ", ", endexpr, ", ", alter, " ", + code, debug, "end", end ) } FOR_FUNC_LOOP { diff --git a/core/src/parser.rs b/core/src/parser.rs index 39b898ee..471925ce 100644 --- a/core/src/parser.rs +++ b/core/src/parser.rs @@ -60,6 +60,9 @@ pub enum ComplexToken { /// Whether the variable(s) is/are local or not. local: bool, + /// Whether the variable(s) is/are const or not. + r#const: bool, + /// The names of the variable(s). names: Vec, @@ -215,10 +218,10 @@ pub enum ComplexToken { TRY_CATCH { /// The code block of the try block. totry: CodeBlock, - + /// An optional code block of the catch block. catch: Option, - + /// The name of the error variable in the catch block. error: Option, }, @@ -796,13 +799,13 @@ impl<'a> ParserInfo<'a> { fn get_prev_expr(&mut self) -> &mut Expression { return match self.internal_stack.last_mut() { Some(last) => last.get_mut(), - None => &mut self.expr + None => &mut self.expr, }; } fn use_internal_stack( &mut self, - f: impl FnOnce(&mut Self) -> Result + f: impl FnOnce(&mut Self) -> Result, ) -> Result<(T, Expression), String> { self.internal_stack.push(Cell::new(Expression::new())); let result = f(self)?; @@ -878,7 +881,13 @@ impl<'a> ParserInfo<'a> { } else { t.into_owned() }; - if self.build_bitwise_op(&BorrowedToken::new(&t2), &mut expr, "bxor", end, notable)? { + if self.build_bitwise_op( + &BorrowedToken::new(&t2), + &mut expr, + "bxor", + end, + notable, + )? { break t; } } @@ -934,7 +943,8 @@ impl<'a> ParserInfo<'a> { let ident = SYMBOL(name.clone()); let mut ctoken = self.build_match_block(name, &|i /* , _ */| { let start = i.peek(0).line(); - let (expr, mut code) = i.use_internal_stack(|i| i.build_expression(None))?; + let (expr, mut code) = + i.use_internal_stack(|i| i.build_expression(None))?; let end = i.look_back(1).line(); if matches!(i.look_back(0).kind(), CURLY_BRACKET_CLOSED | DEFAULT) { i.current -= 1 @@ -943,25 +953,30 @@ impl<'a> ParserInfo<'a> { kind: DEFINE, names: vec_deque![vec_deque![ident.clone()]], values: vec![expr], - line: end + line: end, }); Ok(CodeBlock { start, code, end }) })?; - let MATCH_BLOCK {branches, line, ..} = &mut ctoken else { + let MATCH_BLOCK { branches, line, .. } = &mut ctoken else { unreachable!() }; let last_branch = branches.last().unwrap(); if !(last_branch.0.is_empty() && last_branch.2.is_none()) { - branches.push((Vec::new(), Expression::new(), None, CodeBlock { - start: *line, - code: vec_deque![ALTER { - kind: DEFINE, - names: vec_deque![vec_deque![ident.clone()]], - values: vec![vec_deque![SYMBOL(String::from("nil"))]], - line: *line - }], - end: *line - })) + branches.push(( + Vec::new(), + Expression::new(), + None, + CodeBlock { + start: *line, + code: vec_deque![ALTER { + kind: DEFINE, + names: vec_deque![vec_deque![ident.clone()]], + values: vec![vec_deque![SYMBOL(String::from("nil"))]], + line: *line + }], + end: *line, + }, + )) } self.get_prev_expr().push_back(ctoken); expr.push_back(ident); @@ -972,7 +987,8 @@ impl<'a> ParserInfo<'a> { COALESCE => { let mut leftexpr = Expression::with_capacity(expr.len()); leftexpr.append(&mut expr); - let (rightexpr, mut code) = self.use_internal_stack(|i| i.build_expression(end))?; + let (rightexpr, mut code) = + self.use_internal_stack(|i| i.build_expression(end))?; self.current -= 1; let name = self.get_next_internal_var(); let start = self.at(start).line(); @@ -981,6 +997,7 @@ impl<'a> ParserInfo<'a> { prev_expr.push_back(VARIABLE { line: start, local: true, + r#const: false, names: vec![name.clone()], values: vec![leftexpr], }); @@ -989,7 +1006,7 @@ impl<'a> ParserInfo<'a> { kind: DEFINE, line: t.line(), names: vec_deque![vec_deque![name.clone()]], - values: vec![rightexpr] + values: vec![rightexpr], }); prev_expr.push_back(IF_STATEMENT { condition: vec_deque![name.clone(), SYMBOL(String::from(" == nil"))], @@ -1008,13 +1025,11 @@ impl<'a> ParserInfo<'a> { QUESTION_MARK => { let mut condition = Expression::with_capacity(expr.len()); condition.append(&mut expr); - let (exprtrue, mut codetrue) = self.use_internal_stack( - |i| i.build_expression(Some((COLON, ":"))) - )?; + let (exprtrue, mut codetrue) = + self.use_internal_stack(|i| i.build_expression(Some((COLON, ":"))))?; let t2 = self.look_back(0); - let (exprfalse, mut codefalse) = self.use_internal_stack( - |i| i.build_expression(end) - )?; + let (exprfalse, mut codefalse) = + self.use_internal_stack(|i| i.build_expression(end))?; self.current -= 1; let name = self.get_next_internal_var(); let start = self.at(start).line(); @@ -1023,6 +1038,7 @@ impl<'a> ParserInfo<'a> { prev_expr.push_back(VARIABLE { line: t.line(), local: true, + r#const: false, names: vec![name.clone()], values: Vec::new(), }); @@ -1031,13 +1047,13 @@ impl<'a> ParserInfo<'a> { kind: DEFINE, line: t.line(), names: vec_deque![vec_deque![name.clone()]], - values: vec![exprtrue] + values: vec![exprtrue], }); codefalse.push_back(ALTER { kind: DEFINE, line: t.line(), names: vec_deque![vec_deque![name.clone()]], - values: vec![exprfalse] + values: vec![exprfalse], }); prev_expr.push_back(IF_STATEMENT { condition, @@ -1064,7 +1080,8 @@ impl<'a> ParserInfo<'a> { } } ROUND_BRACKET_OPEN => { - let bracketed_expr = EXPR(self.build_expression(Some((ROUND_BRACKET_CLOSED, ")")))?); + let bracketed_expr = + EXPR(self.build_expression(Some((ROUND_BRACKET_CLOSED, ")")))?); if self.check_val() { expr.push_back(bracketed_expr); break t; @@ -1131,6 +1148,7 @@ impl<'a> ParserInfo<'a> { let line = self.peek(0).line(); self.get_prev_expr().push_back(VARIABLE { local: true, + r#const: false, names: vec![name.clone()], values: vec![safe_expr], line, @@ -1181,6 +1199,7 @@ impl<'a> ParserInfo<'a> { let name = self.get_next_internal_var(); self.expr.push_back(VARIABLE { local: true, + r#const: false, names: vec![name.clone()], values: vec![expr_self], line, @@ -1214,8 +1233,7 @@ impl<'a> ParserInfo<'a> { } } SQUARE_BRACKET_OPEN | SAFE_SQUARE_BRACKET => { - safe_indexing |= - self.build_safe_index(SQUARE_BRACKET_OPEN, t.kind(), expr); + safe_indexing |= self.build_safe_index(SQUARE_BRACKET_OPEN, t.kind(), expr); let qexpr = self.build_expression(Some((SQUARE_BRACKET_CLOSED, "]")))?; expr.push_back(SYMBOL(String::from("[("))); expr.push_back(EXPR(qexpr)); @@ -1333,15 +1351,20 @@ impl<'a> ParserInfo<'a> { CONTINUE if !is_in_other_loop => { if self.options.env_continue == ContinueMode::MoonScript { let line = t.line(); - tokens.push(Token::new(IDENTIFIER, { - if let Some(name) = hascontinue.as_ref() { - name.clone() - } else { - let name = self.get_next_internal_var(); - hascontinue = Some(name.clone()); - name - } - }, line, 0)); + tokens.push(Token::new( + IDENTIFIER, + { + if let Some(name) = hascontinue.as_ref() { + name.clone() + } else { + let name = self.get_next_internal_var(); + hascontinue = Some(name.clone()); + name + } + }, + line, + 0, + )); tokens.push(Token::new(DEFINE, "=", line, 0)); tokens.push(Token::new(TRUE, "true", line, 0)); tokens.push(Token::new(BREAK, "break", line, 0)); @@ -1371,6 +1394,7 @@ impl<'a> ParserInfo<'a> { code = vec_deque![ VARIABLE { local: true, + r#const: false, names: vec![name.clone()], values: vec![vec_deque![SYMBOL(String::from("false"))]], line: start @@ -1468,18 +1492,24 @@ impl<'a> ParserInfo<'a> { Ok(/* (args, types) */ args) } - fn build_elseif_chain(&mut self, condition: Option) -> Result { + fn build_elseif_chain( + &mut self, + condition: Option, + ) -> Result { let condition = match condition { Some(condition) => condition, None => { if self.advance_if(LOCAL) { let start = self.look_back(0).line(); let destructure = self.advance_if(CURLY_BRACKET_OPEN); - let (vars, mut code) = self.use_internal_stack( - |i| i.build_variables(true, start, destructure) - )?; + let (vars, mut code) = self.use_internal_stack(|i| { + i.build_variables(true, false, start, destructure) + })?; let (condition, end) = { - let VARIABLE {names, line: end, ..} = &vars else { + let VARIABLE { + names, line: end, .. + } = &vars + else { unreachable!() }; let mut condition = Expression::with_capacity(names.len()); @@ -1493,7 +1523,7 @@ impl<'a> ParserInfo<'a> { }; code.push_back(vars); code.push_back(self.build_elseif_chain(Some(condition))?); - return Ok(DO_BLOCK(CodeBlock { start, code, end })) + return Ok(DO_BLOCK(CodeBlock { start, code, end })); } self.build_expression(Some((CURLY_BRACKET_OPEN, "{")))? } @@ -1563,6 +1593,7 @@ impl<'a> ParserInfo<'a> { enums.push_back(VARIABLE { line: name.line(), local, + r#const: false, names: vec![name.lexeme()], values: vec![vec_deque![value]], }); @@ -1625,7 +1656,9 @@ impl<'a> ParserInfo<'a> { }*/ #[allow(clippy::type_complexity)] - fn build_destructure_table(&mut self) -> Result<(Vec, Vec, Vec), String> { + fn build_destructure_table( + &mut self, + ) -> Result<(Vec, Vec, Vec), String> { let mut names = Vec::new(); let mut key_names = Vec::new(); let name = self.get_next_internal_var(); @@ -1689,6 +1722,7 @@ impl<'a> ParserInfo<'a> { let mut names = internal_names.into_iter(); prev_expr.push_back(VARIABLE { local: true, + r#const: false, names: vec![names.next().unwrap()], values, line, @@ -1696,6 +1730,7 @@ impl<'a> ParserInfo<'a> { while let (Some(prev_name), Some(name)) = (names.next(), names.next()) { prev_expr.push_back(VARIABLE { local: true, + r#const: false, names: vec![name.clone()], values: vec![vec_deque![SYMBOL(prev_name)]], line, @@ -1706,6 +1741,7 @@ impl<'a> ParserInfo<'a> { fn build_variables( &mut self, local: bool, + r#const: bool, line: usize, destructure: bool, ) -> Result { @@ -1720,6 +1756,7 @@ impl<'a> ParserInfo<'a> { if check == SEMICOLON { self.current += 1; } + if local { Vec::new() } else { @@ -1744,6 +1781,7 @@ impl<'a> ParserInfo<'a> { } Ok(VARIABLE { local, + r#const, names, values, line, @@ -1776,14 +1814,18 @@ impl<'a> ParserInfo<'a> { t.column() )); } - branches.push((Vec::new(), Expression::new(), None, func(self /* , self.locals.clone() */)?)); + branches.push(( + Vec::new(), + Expression::new(), + None, + func(self /* , self.locals.clone() */)?, + )); self.assert(CURLY_BRACKET_CLOSED, "}")?; false } IF => { - let (extra_if, internal_expr) = self.use_internal_stack(|i| - i.build_expression(Some((ARROW, "=>"))) - )?; + let (extra_if, internal_expr) = + self.use_internal_stack(|i| i.build_expression(Some((ARROW, "=>"))))?; branches.push(( Vec::new(), internal_expr, @@ -1801,7 +1843,7 @@ impl<'a> ParserInfo<'a> { let extra_if = match t.kind() { ARROW => None, IF => Some(i.build_expression(Some((ARROW, "=>")))?), - _ => return Err(i.expected("=>", &t.lexeme(), t.line(), t.column())) + _ => return Err(i.expected("=>", &t.lexeme(), t.line(), t.column())), }; Ok((expr, extra_if)) })?; @@ -1823,7 +1865,7 @@ impl<'a> ParserInfo<'a> { conditions, internal_expr, extra_if, - func(self /* , self.locals.clone() */)? + func(self /* , self.locals.clone() */)?, )); !self.advance_if(CURLY_BRACKET_CLOSED) } @@ -1839,14 +1881,15 @@ impl<'a> ParserInfo<'a> { fn build_loop( &mut self, code: Option, - end: OptionalEnd + end: OptionalEnd, ) -> Result<(Expression, CodeBlock), String> { let start = self.peek(0).line(); - let (condition, mut internal_code) = self.use_internal_stack(|i| i.build_expression(end))?; + let (condition, mut internal_code) = + self.use_internal_stack(|i| i.build_expression(end))?; let end = self.look_back(1).line(); let code = match code { Some(code) => code, - None => self.build_loop_block()? + None => self.build_loop_block()?, }; if !internal_code.is_empty() { internal_code.push_back(RETURN_EXPR(Some(vec![condition]))); @@ -1855,7 +1898,11 @@ impl<'a> ParserInfo<'a> { local: true, name: vec_deque![SYMBOL(function_name.clone())], args: vec![], - code: CodeBlock { start, code: internal_code, end } + code: CodeBlock { + start, + code: internal_code, + end, + }, }); Ok((vec_deque![SYMBOL(format_clue!(function_name, "()"))], code)) } else { @@ -1874,12 +1921,7 @@ impl<'a> ParserInfo<'a> { let safe_indexing = self.build_identifier_internal(&mut expr)?; if strict && !matches!(expr.back(), Some(CALL(..))) { let t = self.look_back(0); - return Err(self.expected_before( - "", - &t.lexeme(), - t.line(), - t.column() - )) + return Err(self.expected_before("", &t.lexeme(), t.line(), t.column())); } if safe_indexing { let call = if strict { expr.pop_back() } else { None }; @@ -1899,6 +1941,20 @@ impl<'a> ParserInfo<'a> { fn parse_token_local_global(&mut self, t: &BorrowedToken) -> Result<(), String> { let local = t.kind() == LOCAL; + let r#const = t.kind() == CONST || self.advance_if(CONST); + if r#const + && (self.options.env_target.is_none() + || self + .options + .env_target + .is_some_and(|lua| lua != LuaVersion::Lua54)) + { + println!( + "Warning: Using `const` without targeting Lua 5.4 {}:{}", + t.line(), + t.column() + ); + } match self.peek(0).kind() { FN => { let function = self.build_function(local)?; @@ -1910,7 +1966,7 @@ impl<'a> ParserInfo<'a> { } _ => { let destructure = self.advance_if(CURLY_BRACKET_OPEN); - let vars = self.build_variables(local, t.line(), destructure)?; + let vars = self.build_variables(local, r#const, t.line(), destructure)?; self.expr.push_back(vars); } } @@ -1918,6 +1974,20 @@ impl<'a> ParserInfo<'a> { } fn parse_token_static(&mut self, t: &BorrowedToken) -> Result<(), String> { + let r#const = t.kind() == CONST || self.advance_if(CONST); + if r#const + && (self.options.env_target.is_none() + || self + .options + .env_target + .is_some_and(|lua| lua != LuaVersion::Lua54)) + { + println!( + "Warning: Using `const` without targeting Lua 5.4 {}:{}", + t.line(), + t.column() + ); + } match self.peek(0).kind() { FN => { let function = vec_deque![self.build_function(true)?]; @@ -1928,7 +1998,7 @@ impl<'a> ParserInfo<'a> { self.compile_static(enums)?; } _ => { - let vars = vec_deque![self.build_variables(true, t.line(), false)?]; + let vars = vec_deque![self.build_variables(true, r#const, t.line(), false)?]; self.compile_static(vars)?; } } @@ -2073,7 +2143,9 @@ impl<'a> ParserInfo<'a> { } fn parse_token_round_bracket_open(&mut self) -> Result<(), String> { - let expr = vec_deque![EXPR(self.build_expression(Some((ROUND_BRACKET_CLOSED, ")")))?)]; + let expr = vec_deque![EXPR( + self.build_expression(Some((ROUND_BRACKET_CLOSED, ")")))? + )]; let mut target_expr = Expression::with_capacity(2); self.build_round_brackets(expr, &mut target_expr, true)?; self.expr.append(&mut target_expr); @@ -2103,7 +2175,11 @@ impl<'a> ParserInfo<'a> { fn parse_token_while(&mut self, line: usize) -> Result<(), String> { let (condition, code) = self.build_loop(None, Some((CURLY_BRACKET_OPEN, "{")))?; - self.expr.push_back(WHILE_LOOP { condition, code, line }); + self.expr.push_back(WHILE_LOOP { + condition, + code, + line, + }); Ok(()) } @@ -2111,7 +2187,11 @@ impl<'a> ParserInfo<'a> { let (mut condition, code) = self.build_loop(None, Some((CURLY_BRACKET_OPEN, "{")))?; condition.push_front(SYMBOL(String::from("not ("))); condition.push_back(SYMBOL(String::from(")"))); - self.expr.push_back(WHILE_LOOP { condition, code, line }); + self.expr.push_back(WHILE_LOOP { + condition, + code, + line, + }); Ok(()) } @@ -2121,13 +2201,21 @@ impl<'a> ParserInfo<'a> { match t.kind() { UNTIL => { let (condition, code) = self.build_loop(Some(code), None)?; - self.expr.push_back(LOOP_UNTIL { condition, code, line: t.line() }) + self.expr.push_back(LOOP_UNTIL { + condition, + code, + line: t.line(), + }) } WHILE => { let (mut condition, code) = self.build_loop(Some(code), None)?; condition.push_front(SYMBOL(String::from("not ("))); condition.push_back(SYMBOL(String::from(")"))); - self.expr.push_back(LOOP_UNTIL { condition, code, line: t.line() }) + self.expr.push_back(LOOP_UNTIL { + condition, + code, + line: t.line(), + }) } _ => self.expr.push_back(WHILE_LOOP { condition: vec_deque![SYMBOL(String::from("true"))], @@ -2222,7 +2310,7 @@ impl<'a> ParserInfo<'a> { self.expr.push_back(RETURN_EXPR(exprs)); if !self.ended() { let t = self.look_back(0); - return Err(self.expected("", &t.lexeme(), t.line(), t.column())) + return Err(self.expected("", &t.lexeme(), t.line(), t.column())); } Ok(()) } @@ -2303,7 +2391,7 @@ pub fn parse_tokens( while !i.ended() { let t = i.advance(); match t.kind() { - LOCAL | GLOBAL => i.parse_token_local_global(&t)?, + LOCAL | GLOBAL | CONST => i.parse_token_local_global(&t)?, STATIC => i.parse_token_static(&t)?, METHOD => i.parse_token_method()?, IDENTIFIER => i.parse_token_identifier(&t)?, diff --git a/core/src/scanner.rs b/core/src/scanner.rs index b5a298e1..f49adbfa 100644 --- a/core/src/scanner.rs +++ b/core/src/scanner.rs @@ -54,7 +54,7 @@ pub enum TokenType { //keywords IF, ELSEIF, ELSE, FOR, OF, IN, WITH, WHILE, META, GLOBAL, UNTIL, - LOCAL, FN, METHOD, RETURN, TRUE, FALSE, NIL, LOOP, STATIC, ENUM, + LOCAL, CONST, FN, METHOD, RETURN, TRUE, FALSE, NIL, LOOP, STATIC, ENUM, CONTINUE, BREAK, TRY, CATCH, MATCH, DEFAULT, STRUCT, EXTERN, CONSTRUCTOR, EOF, @@ -602,6 +602,7 @@ static KEYWORDS: phf::Map<&'static [u8], KeywordType> = phf_map! { b"while" => KeywordType::Lua(WHILE), b"until" => KeywordType::Lua(UNTIL), b"local" => KeywordType::Lua(LOCAL), + b"const" => KeywordType::Lua(CONST), b"return" => KeywordType::Lua(RETURN), b"true" => KeywordType::Lua(TRUE), b"false" => KeywordType::Lua(FALSE), diff --git a/examples/const.clue b/examples/const.clue new file mode 100644 index 00000000..31bc6d3a --- /dev/null +++ b/examples/const.clue @@ -0,0 +1,7 @@ +const test1 = "test1" +local const test2 = "test2" +static const test3 = "test3" + +print(test1) +print(test2) +print(test3) \ No newline at end of file