diff --git a/src/ast_compiler.rs b/src/ast_compiler.rs index b4a2397..1a9068b 100644 --- a/src/ast_compiler.rs +++ b/src/ast_compiler.rs @@ -1,14 +1,12 @@ -use crate::ast_compiler::Expression::{ - FunctionCall, NamedParameter, Stop, Variable, -}; +use crate::ast_compiler::Expression::{FunctionCall, NamedParameter, Stop, Variable}; use crate::errors::CompilerError::{ self, Expected, IncompatibleTypes, ParseError, TooManyParameters, TypeError, UndeclaredVariable, UnexpectedIndent, UninitializedVariable, }; use crate::errors::CompilerErrorAtLine; use crate::tokens::TokenType::{ - Bang, Bool, Char, Colon, Date, Dot, Eof, Eol, Equal, F32, F64, False, FloatingPoint, Fn, - Greater, GreaterEqual, GreaterGreater, I32, I64, Identifier, Indent, Integer, LeftBrace, + Bang, Bool, Char, Colon, Date, DateTime, Dot, Eof, Eol, Equal, F32, F64, False, FloatingPoint, + Fn, Greater, GreaterEqual, GreaterGreater, I32, I64, Identifier, Indent, Integer, LeftBrace, LeftBracket, LeftParen, Less, LessEqual, LessLess, Let, ListType, MapType, Minus, Object, Plus, Print, RightBrace, RightBracket, RightParen, SignedInteger, SingleRightArrow, Slash, Star, StringType, True, U32, U64, UnsignedInteger, @@ -469,7 +467,7 @@ impl AstCompiler { Expression::Literal { line: self.peek().line, literaltype: StringType, - value: Value::String(self.previous().lexeme.to_string()), + value: Value::String(self.previous().lexeme.clone()), } } else if self.match_token(vec![Char]) { Expression::Literal { @@ -477,6 +475,19 @@ impl AstCompiler { literaltype: Char, value: Value::Char(self.previous().lexeme.chars().next().unwrap()), } + } else if self.match_token(vec![DateTime]) { + Expression::Literal { + line: self.peek().line, + literaltype: DateTime, + value: Value::DateTime( + chrono::DateTime::parse_from_str( + &self.previous().lexeme, + "%Y-%m-%d %H:%M:%S%.3f %z", + ) + .map_err(|e| self.raise(ParseError(self.previous().lexeme.clone())))? + .into(), + ), + } } else if self.match_token(vec![LeftParen]) { let expr = self.expression()?; self.consume(RightParen, Expected("')' after expression."))?; diff --git a/src/compiler_tests.rs b/src/compiler_tests.rs index 4a98887..e838e58 100644 --- a/src/compiler_tests.rs +++ b/src/compiler_tests.rs @@ -2,6 +2,7 @@ mod tests { use crate::value::Value; use crate::{compile, run}; + use chrono::{DateTime, FixedOffset, NaiveDate, TimeZone}; #[test] fn literal_int() { @@ -118,20 +119,20 @@ object Person: assert!(r.is_ok()); // does nothing runtime } -// #[test] -// fn object_() { -// let r = run( -// r#" -// object Person: -// name: string -// -// let p = Person(name: "Sander") -// print p -// "#, -// ); -// println!("{:?}", r); -// assert!(r.is_ok()); -// } + // #[test] + // fn object_() { + // let r = run( + // r#" + // object Person: + // name: string + // + // let p = Person(name: "Sander") + // print p + // "#, + // ); + // println!("{:?}", r); + // assert!(r.is_ok()); + // } #[test] fn literal_map() { @@ -202,6 +203,16 @@ m"#); assert_eq!(run(r#"0x10 + 0x20"#), Ok(Value::U32(48))); } + #[test] + fn date_literal() { + assert_eq!( + run(r#"t"2025-11-09 16:44:28.000 +0100""#), + Ok(Value::DateTime( + DateTime::parse_from_str("2025-11-09 16:44:28.000 +0100", "%Y-%m-%d %H:%M:%S%.3f %z").unwrap().into() + )) + ); + } + // #[test] // fn package() { // assert_eq!(run(r#"a.b.c()"#), Ok(Value::U32(48))); diff --git a/src/scanner.rs b/src/scanner.rs index aa1ce2e..98b9eec 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -111,6 +111,11 @@ impl Scanner { } '\'' => self.char()?, '"' => self.string()?, + 't' => { + if self.match_next('"') { + self.datetime()?; + } + } '\r' | '\t' | ' ' => {} '\n' => { self.line += 1; @@ -220,6 +225,18 @@ impl Scanner { CompilerErrorAtLine::raise(error, self.line) } + fn datetime(&mut self) -> Result<(), CompilerErrorAtLine> { + while self.peek() != '"' && !self.is_at_end() { + self.advance(); + } + self.advance(); + let value: String = self.chars[self.start + 2..self.current - 1] + .iter() + .collect(); + self.add_token_with_value(TokenType::DateTime, value); + Ok(()) + } + fn string(&mut self) -> Result<(), CompilerErrorAtLine> { while self.peek() != '"' && !self.is_at_end() { if self.peek() == '\n' { diff --git a/src/symbol_builder.rs b/src/symbol_builder.rs index 1b282ac..d72c752 100644 --- a/src/symbol_builder.rs +++ b/src/symbol_builder.rs @@ -2,11 +2,7 @@ use crate::ast_compiler::{Expression, Parameter, Statement}; use crate::errors::CompilerError; use crate::errors::CompilerError::{IncompatibleTypes, TypeError}; use crate::tokens::{Token, TokenType}; -use crate::tokens::TokenType::{ - Bool, Date, F32, F64, FloatingPoint, Greater, GreaterEqual, I32, I64, Integer, Less, LessEqual, - ListType, MapType, Minus, Object, Plus, SignedInteger, StringType, U32, U64, Unknown, - UnsignedInteger, -}; +use crate::tokens::TokenType::{Bool, Date, F32, F64, FloatingPoint, Greater, GreaterEqual, I32, I64, Integer, Less, LessEqual, ListType, MapType, Minus, Object, Plus, SignedInteger, StringType, U32, U64, Unknown, UnsignedInteger, DateTime}; use log::debug; use std::collections::HashMap; @@ -139,6 +135,7 @@ pub fn calculate_type( FloatingPoint => F64, Bool => Bool, Date => Date, + DateTime => DateTime, ListType => ListType, MapType => MapType, Object => Object, diff --git a/src/tokens.rs b/src/tokens.rs index 1edf92a..96c0bc9 100644 --- a/src/tokens.rs +++ b/src/tokens.rs @@ -82,6 +82,7 @@ pub enum TokenType { Star, StringType, True, + DateTime, U32, U64, Unknown, @@ -156,6 +157,7 @@ impl fmt::Display for TokenType { TokenType::SingleRightArrow => write!(f, "->"), TokenType::Slash => write!(f, "/"), TokenType::Star => write!(f, "*"), + TokenType::DateTime => write!(f, "t\""), TokenType::True => write!(f, "true"), TokenType::Unknown => write!(f, "?"), TokenType::Void => write!(f, "()"), diff --git a/src/value.rs b/src/value.rs index 79fa297..387ccaf 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,5 +1,5 @@ use crate::errors::ValueError; -use chrono::{DateTime, Utc}; +use chrono::{DateTime, Local, Utc}; use std::cmp::Ordering; use std::collections::HashMap; use std::fmt::{Display, Formatter}; @@ -23,7 +23,7 @@ pub enum Value { String(String), Char(char), Bool(bool), - Date(DateTime), + DateTime(DateTime), Enum, List(Vec), Map(HashMap), @@ -144,7 +144,7 @@ impl Into for bool { impl Into for DateTime { fn into(self) -> Value { - Value::Date(self) + Value::DateTime(self) } } @@ -160,7 +160,7 @@ impl Display for Value { &Value::F32(v) => write!(f, "{}", v), &Value::F64(v) => write!(f, "{}", v), &Value::Char(v) => write!(f, "{}", v), - &Value::Date(v) => write!(f, "{}", v), + &Value::DateTime(v) => write!(f, "{}", v), &Value::Enum => write!(f, "enum"), &Value::ObjectType(o) => write!(f, "{}: {:?}", o.definition, o.fields), &Value::List(v) => write!(f, "{:?}", v), @@ -383,7 +383,7 @@ impl PartialEq for Value { (Value::Bool(a), Value::Bool(b)) => a == b, (Value::String(a), Value::String(b)) => a == b, (Value::Char(a), Value::Char(b)) => a == b, - (Value::Date(a), Value::Date(b)) => a == b, + (Value::DateTime(a), Value::DateTime(b)) => a == b, (Value::List(a), Value::List(b)) => a == b, (Value::Map(a), Value::Map(b)) => { let mut equal = true; @@ -415,7 +415,7 @@ impl PartialOrd for Value { (Value::F64(a), Value::F64(b)) => Some(a.partial_cmp(b)?), (Value::String(a), Value::String(b)) => Some(a.partial_cmp(b)?), (Value::Char(a), Value::Char(b)) => Some(a.partial_cmp(b)?), - (Value::Date(a), Value::Date(b)) => Some(a.partial_cmp(b)?), + (Value::DateTime(a), Value::DateTime(b)) => Some(a.partial_cmp(b)?), _ => None, } } @@ -436,7 +436,7 @@ impl Hash for Value { Value::String(s) => s.hash(state), Value::Char(c) => c.hash(state), Value::Bool(b) => b.hash(state), - Value::Date(d) => d.hash(state), + Value::DateTime(d) => d.hash(state), Value::List(l) => l.hash(state), _ => {} }