Skip to content

Commit 146920b

Browse files
authored
feat: add basic type checking for expressions (#34)
**Description** This PR adds type information to the TokenId and TokenCte nodes and performs type checking on assignments and arithmetic expressions
1 parent 05feea1 commit 146920b

File tree

8 files changed

+455
-120
lines changed

8 files changed

+455
-120
lines changed

examples/arithmetic.lm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
main(){
22
init {
3-
x : float
3+
x, c, r, z, f : int
44
}
55

66
x := 27 - c

examples/hello_world.lm

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,27 @@ main(){
55
a, b, c, d : float
66
var1234 : string
77
}
8-
a := 4+3
9-
b := 9
8+
a := 4.0+3.0
9+
x := 9
1010
a := 5.25
1111
b := -5.25
12-
c := "test1234"
13-
d := 1
12+
var1234 := "test1234"
13+
d := 1.0
1414

1515
while(a > b) {
16-
a := 1
16+
a := 1.0
1717
}
1818

1919
if(a > b and c > d) {
20-
a := 1
20+
a := 1.0
2121
}
2222
else {
23-
b := 1
23+
b := 1.0
2424
}
2525

26-
b := 1
26+
b := 1.0
2727

2828
if(not b){
29-
a := 1
29+
a := 1.0
3030
}
3131
}

inputs/test.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,10 @@ read(f6f)
5555
#+ Ejemplo de error por float invalido +#
5656
#+ x := 1001247380987123904721309473201974012938740921374091237409127340983217094874.1234 +#
5757

58+
#+ Ejemplo de error por uso de variable no declarada +#
59+
#+ nodeclarada1 := 1234 +#
60+
61+
#+ Ejemplo de error por asignacion de con tipos incorrectos +#
62+
#+ a1 := 33 + 1.33 +#
5863

5964
a1 := convDate(01-02-1900)

src/compiler/ast.rs

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::grammar::types::ComparisonOp;
1+
use crate::grammar::types::{ComparisonOp, DataType};
22
use std::{
33
array,
44
cell::Cell,
@@ -75,6 +75,7 @@ pub struct Node {
7575
parent: Cell<Option<Rc<Node>>>,
7676
left_child: Option<Rc<Node>>,
7777
right_child: Option<Rc<Node>>,
78+
pub r#type: Option<ExpressionType>,
7879
}
7980

8081
impl Debug for Node {
@@ -84,12 +85,13 @@ impl Debug for Node {
8485
}
8586

8687
impl Node {
87-
pub fn new_leaf(value: NodeValue) -> Self {
88+
pub fn new_leaf(value: NodeValue, node_type: Option<ExpressionType>) -> Self {
8889
Self {
8990
value,
9091
parent: Cell::new(None),
9192
left_child: None,
9293
right_child: None,
94+
r#type: node_type,
9395
}
9496
}
9597
}
@@ -109,6 +111,33 @@ impl Display for NodeValue {
109111
}
110112
}
111113

114+
#[derive(Clone, Debug, PartialEq)]
115+
pub enum ExpressionType {
116+
Float,
117+
Int,
118+
String,
119+
}
120+
121+
impl Display for ExpressionType {
122+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123+
match self {
124+
Self::Float => write!(f, "FLOAT"),
125+
Self::Int => write!(f, "INT"),
126+
Self::String => write!(f, "STRING"),
127+
}
128+
}
129+
}
130+
131+
impl From<DataType> for ExpressionType {
132+
fn from(value: DataType) -> Self {
133+
match value {
134+
DataType::FloatType(_) => ExpressionType::Float,
135+
DataType::IntType(_) => ExpressionType::Int,
136+
DataType::StringType(_) => ExpressionType::String,
137+
}
138+
}
139+
}
140+
112141
#[derive(Clone, Debug)]
113142
pub enum AstAction {
114143
Plus,
@@ -182,7 +211,9 @@ impl From<ComparisonOp> for AstAction {
182211
impl Default for Ast {
183212
fn default() -> Self {
184213
Self {
185-
tree: array::from_fn(|_| Rc::new(Node::new_leaf(NodeValue::Value("".to_string())))),
214+
tree: array::from_fn(|_| {
215+
Rc::new(Node::new_leaf(NodeValue::Value("".to_string()), None))
216+
}),
186217
expression_stack: Vec::new(),
187218
term_stack: Vec::new(),
188219
comparision_op_stack: Vec::new(),
@@ -215,6 +246,7 @@ impl Ast {
215246
left_child_ptr: AstNodeRef,
216247
right_child_ptr: AstNodeRef,
217248
dest_ptr: AstPtr,
249+
r#type: Option<ExpressionType>,
218250
) -> Rc<Node> {
219251
let left_child = match left_child_ptr {
220252
AstNodeRef::Ptr(ptr) => self.tree.get(ptr as usize).cloned(),
@@ -230,6 +262,7 @@ impl Ast {
230262
parent: Cell::new(None),
231263
left_child: left_child.clone(),
232264
right_child: right_child.clone(),
265+
r#type,
233266
});
234267

235268
if let Some(left) = left_child {
@@ -243,8 +276,13 @@ impl Ast {
243276
node
244277
}
245278

246-
pub fn create_leaf(&mut self, value: String, dest_ptr: AstPtr) -> Rc<Node> {
247-
let leaf = Rc::new(Node::new_leaf(NodeValue::Value(value)));
279+
pub fn create_leaf(
280+
&mut self,
281+
value: String,
282+
dest_ptr: AstPtr,
283+
node_type: Option<ExpressionType>,
284+
) -> Rc<Node> {
285+
let leaf = Rc::new(Node::new_leaf(NodeValue::Value(value), node_type));
248286
self.tree[dest_ptr as usize] = leaf.clone();
249287
leaf
250288
}
@@ -273,7 +311,15 @@ impl Ast {
273311
) -> Result<usize, io::Error> {
274312
let node_name = format!("n{node_count:0>3}");
275313
writeln!(file, " {node_name:0>3} ;")?;
276-
writeln!(file, " {node_name:0>3} [label=\"{:}\"] ;", node.value)?;
314+
writeln!(
315+
file,
316+
" {node_name:0>3} [label=\"{}{}\"] ;",
317+
node.value,
318+
node.r#type
319+
.as_ref()
320+
.map(|t| format!(" | {t}"))
321+
.unwrap_or_default()
322+
)?;
277323
if let Some(left_child) = &node.left_child {
278324
node_count += 1;
279325
writeln!(file, " {node_name} -- n{node_count:0>3} ;")?;

src/compiler/context.rs

Lines changed: 63 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,13 @@ impl CompilerContext {
156156
self.symbol_table.contains(symbol)
157157
}
158158

159+
pub fn get_symbol_type(&self, symbol_name: &str) -> Option<Option<DataType>> {
160+
self.symbol_table
161+
.iter()
162+
.find(|x| x.name == symbol_name)
163+
.map(|x| x.data_type.clone())
164+
}
165+
159166
pub fn create_ast_graph(&mut self, from: AstPtr) -> Result<(), CompilerError> {
160167
self.ast
161168
.graph_ast(
@@ -167,66 +174,85 @@ impl CompilerContext {
167174
}
168175
}
169176

170-
#[derive(Clone, Debug)]
171-
pub enum SymbolTableElement {
172-
VarDeclaration(String, DataType, usize),
173-
IntLiteral(TokenIntLiteral),
174-
FloatLiteral(TokenFloatLiteral),
175-
StringLiteral(TokenStringLiteral),
177+
#[derive(Default)]
178+
pub struct SymbolTableElement {
179+
pub name: String,
180+
pub data_type: Option<DataType>,
181+
pub value: Option<String>,
182+
pub length: Option<usize>,
176183
}
177184

178185
impl Display for SymbolTableElement {
179186
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180-
match self {
181-
Self::FloatLiteral(float) => write!(
182-
f,
183-
"{}|CONST_FLOAT|{}|{}",
184-
float.original,
185-
float.original,
186-
float.original.len()
187-
)?,
188-
Self::IntLiteral(int) => {
189-
write!(f, "{}|CONST_INT|{}|{}", int, int, int.to_string().len())?
190-
}
191-
Self::StringLiteral(string) => {
192-
write!(f, "{}|CONST_STRING|{}|{}", string, string, string.len())?
193-
}
194-
Self::VarDeclaration(token, r#type, length) => {
195-
write!(f, "{}|{}|-|{}", token, r#type, length)?
196-
}
197-
};
198-
Ok(())
187+
let name = &self.name;
188+
let data_type = self
189+
.data_type
190+
.as_ref()
191+
.map(|r#type| r#type.to_string())
192+
.unwrap_or_else(|| String::from("-"));
193+
let value = self
194+
.value
195+
.as_ref()
196+
.cloned()
197+
.unwrap_or_else(|| String::from("-"));
198+
let length = self
199+
.length
200+
.map(|length| length.to_string())
201+
.unwrap_or_else(|| String::from("-"));
202+
203+
write!(f, "{name}|{data_type}|{value}|{length}")
199204
}
200205
}
201206

202207
impl PartialEq for SymbolTableElement {
203208
fn eq(&self, other: &Self) -> bool {
204-
match (self, other) {
205-
(Self::FloatLiteral(token0), Self::FloatLiteral(token1)) => token0 == token1,
206-
(Self::IntLiteral(token0), Self::IntLiteral(token1)) => token0 == token1,
207-
(Self::StringLiteral(token0), Self::StringLiteral(token1)) => token0 == token1,
208-
(Self::VarDeclaration(token0, _, _), Self::VarDeclaration(token1, _, _)) => {
209-
token0 == token1
210-
}
211-
_ => false,
212-
}
209+
self.name == other.name
213210
}
214211
}
215212

213+
impl Eq for SymbolTableElement {}
214+
216215
impl From<TokenIntLiteral> for SymbolTableElement {
217216
fn from(value: TokenIntLiteral) -> Self {
218-
Self::IntLiteral(value)
217+
let mut name = String::with_capacity(value.original.len() + 1);
218+
name.push('_');
219+
name.push_str(&value.original);
220+
221+
Self {
222+
name,
223+
data_type: None,
224+
value: Some(value.original),
225+
length: None,
226+
}
219227
}
220228
}
221229

222230
impl From<TokenFloatLiteral> for SymbolTableElement {
223231
fn from(value: TokenFloatLiteral) -> Self {
224-
Self::FloatLiteral(value)
232+
let mut name = String::with_capacity(value.original.len() + 1);
233+
name.push('_');
234+
name.push_str(&value.original);
235+
236+
Self {
237+
name: value.original.clone(),
238+
data_type: None,
239+
value: Some(value.original),
240+
length: None,
241+
}
225242
}
226243
}
227244

228245
impl From<TokenStringLiteral> for SymbolTableElement {
229246
fn from(value: TokenStringLiteral) -> Self {
230-
Self::StringLiteral(value)
247+
let mut name = String::with_capacity(value.len() + 1);
248+
name.push('_');
249+
name.push_str(&value);
250+
251+
Self {
252+
name,
253+
data_type: None,
254+
length: Some(value.len()),
255+
value: Some(value),
256+
}
231257
}
232258
}

src/compiler/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ pub enum CompilerError {
1313
Lexer(String),
1414
#[error("Context error: {0}")]
1515
Context(String),
16+
#[error("Type mismatch error: {0}")]
17+
TypeMismatch(String),
18+
#[error("Use of undeclared variable: {0}")]
19+
UndeclaredVariable(String),
1620
#[error("IO error: {0}")]
1721
IO(String),
1822
#[error("Compiler internal error: {0}. This is a bug.")]

0 commit comments

Comments
 (0)