Skip to content

Commit d38927a

Browse files
authored
Merge pull request #14 from Java-rs/typechecking
Typechecking
2 parents c2a62ce + 42c8943 commit d38927a

22 files changed

+406
-264
lines changed

docs/Project-Doc.md

+36-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,46 @@
1+
## Supported types
2+
- Welche Types, Strukturen und deren Kombinationen werden unterstützt?
3+
14
## Parser
25

36
- Wer hat welche Arbeit am Parser gemacht?
47
- Wie wurde Pest fürs Parsing eingesetzt? (sehr ähnlich zu ANTLR)
58

69
## Typchecker
710

8-
- Wer hat welche Arbeit am Typchecker gemacht?
11+
Geschrieben von: Maximilian Floto, Philipp Wolf
12+
13+
Der Typechecker akzeptiert einen Abstract Syntax Tree (AST) und gibt einen getypten AST (TAST) zurück.
14+
Er führt eine umfassende Analyse durch, um die Typen aller Variablen und Ausdrücke im Code zu bestimmen.
15+
Er stellt sicher, dass jede Variable vor ihrer Verwendung korrekt deklariert und initialisiert wurde, wodurch potenzielle Fehler in der Anwendung vermieden werden.
16+
Er bestimmt die Typen aller Ausdrücke und Variablen und überprüft, ob alle Variablen vor ihrer Verwendung korrekt deklariert und initialisiert wurden.
17+
18+
Funktionsweise des Typecheckers:
19+
Der Typechecker iteriert über alle übergebenen Klassen und prüft auf mehrfache Klassendeklarationen. Die Felddeklarationen werden in einem neuen getypten Klassenobjekt gespeichert, in dem alle weiteren getypten Methoden und deren Statements gespeichert werden. Anschließend iteriert der Typechecker über alle Methoden und prüft auf mehrfache Methodendeklarationen und typisiert die Methodenparameter. Nachdem alle Statements typisiert wurden, wird der Rückgabetyp der Methode geprüft und die Methode im getypten Klassenobjekt gespeichert. Nach dem Überprüfen und Typisieren der Klasse wird diese in einen Vektor an getypten Klassen gespeichert. Nachdem alle Klassen getypt wurden, wird der Vektor an getypten Klassen zurückgegeben.
20+
21+
Folgende Funktionen werden vom Typechecker übernommen:
22+
- Liest alle definierten Types/Strukturen
23+
- Typisierung aller Variablen und Ausdrücke
24+
- Checken von mehreren Klassen
25+
- Checken der Rückgabe-Typen von Methoden
26+
- Ersetzen von LocalOrFieldVar durch LocalVar oder FieldVar
27+
28+
29+
Folgende Fehler werden vom Typechecker erkannt:
30+
- Mehrfache Deklaration einer Klasse
31+
- Mehrfache Deklaration einer Methode
32+
- Type-Mismatch bei Methodenrückgabe
33+
- Type-Mismatch bei Methodenaufruf
34+
- Type-Mismatch bei Methodenparametern
35+
- Type-Mismatch bei FieldDecl
36+
- Type-Mismatch bei Unary/Binary-Operationen
37+
- Mehrfache Deklaration von FieldDecl
38+
- Mehrfache Deklaration von LocalOrFieldVar
39+
- Nicht deklarierte Variable
40+
- Unbekannte Methode bei Methodenaufruf
41+
- Verwendung einer nicht deklarierten Variable
42+
- Panic bei TypedExpr in AST
43+
- Bedingung von If/While-Statement ist kein Bool
944

1045
## Codegenerierung
1146

docs/User-Doc.md

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ TBD
77

88
## Typchecker
99

10+
1. Projekt bauen: `cargo build`
11+
2. Go to lib folder: `cd lib`
12+
3. Typechecker tests ausführen: `cargo test test_typechecker`
13+
14+
Spezifischen Test ausführen: `cargo test <test_name>::test_typechecker`
15+
1016
## Codegenerierung
1117

1218
## Testing

lib/src/codegen/bytecode.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1+
#![allow(unused)]
12
//! Utilities for bytecode generation
23
3-
use crate::codegen::ir::*;
4-
use crate::types::*;
4+
// use crate::codegen::ir::*;
5+
// use crate::types::*;

lib/src/codegen/ir.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#![allow(non_camel_case_types)]
2+
#![allow(unused)]
3+
#![allow(non_snake_case)]
24

35
use crate::typechecker::*;
46
use crate::types;

lib/src/parser/JavaGrammar.pest

+11-7
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@ Program = {ClassDecl+}
66

77
ClassDecl = {"class" ~ Identifier ~ "{" ~ (MethodDecl|FieldDecl)* ~ "}"}
88

9-
FieldDecl = {JType ~ FieldVarDecl+}
9+
FieldDecl = {JType ~ FieldVarDeclList ~ ";"}
1010

1111
MethodDecl = {JType ~ Identifier ~ "(" ~ ParamDeclList? ~ ")" ~ BlockStmt}
1212

1313
ParamDeclList = {ParamDecl ~ (","~ParamDecl)*}
1414

1515
ParamDecl = {JType ~ Identifier}
1616

17+
FieldVarDeclList = {FieldVarDecl ~ (","~FieldVarDeclList)*}
18+
1719
FieldVarDecl = {Identifier ~ ("="~Expr)?}
1820

1921
JType = {PrimitiveType | Identifier}
@@ -56,27 +58,29 @@ MethodCallExpr = {(Identifier|InstVarExpr) ~ "(" ~ ParamList? ~ ")"}
5658
ParamList = {Expr ~ (","~Expr)*}
5759

5860
// @Note we do not support `super` at the moment
59-
Expr = {Prec3BinExpr | NonBinaryExpr}
61+
Expr = {NonBinaryExpr | Prec3BinExpr}
6062

6163
NonBinaryExpr = { ThisExpr
62-
| Identifier // LocalOrFieldVar
64+
| JNull
6365
| InstVarExpr
6466
| UnaryExpr
67+
| ParanthesizedExpr
6568
| IntLiteral
6669
| BoolLiteral
6770
| CharLiteral
6871
| StrLiteral
69-
| JNull
70-
| ParanthesizedExpr
72+
| Identifier // LocalOrFieldVar
7173
| StmtExpr}
7274

7375
ThisExpr = {"this"}
7476
JNull = {"null"}
7577

7678
IntLiteral = {NUMBER+}
7779
BoolLiteral = {"true" | "false"}
78-
CharLiteral = {"'" ~ ASCII ~ "'"}
79-
StrLiteral = {"\"" ~ ASCII* ~ "\""}
80+
CharLiteral = { "'" ~ (!("'" | "\\") ~ ANY | EscapedChar) ~ "'"}
81+
StrLiteral = { "\"" ~ (!("\"" | "\\") ~ ANY | EscapedChar)* ~ "\""}
82+
EscapedChar = { "\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t")
83+
| "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4})}
8084

8185
InstVarExpr = {(Identifier|ThisExpr) ~ "." ~ InnerInstVarExpr}
8286
InnerInstVarExpr = {Identifier ~ ("." ~ (InnerInstVarExpr|Identifier))?}

lib/src/parser/mod.rs

-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,2 @@
11
mod parser;
2-
#[cfg(test)]
3-
mod test;
4-
52
pub use parser::*;

lib/src/parser/parser.rs

+43-24
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
#![allow(non_camel_case_types)]
2+
#![allow(unused)]
3+
#![allow(non_snake_case)]
4+
15
extern crate pest;
26
extern crate pest_derive;
37

@@ -11,7 +15,7 @@ use pest_derive::Parser;
1115
#[grammar = "../lib/src/parser/JavaGrammar.pest"]
1216
struct ExampleParser;
1317

14-
pub fn parse_Programm(file: &str) -> Result<Vec<Class>, Error<Rule>> {
18+
pub fn parse_programm(file: &str) -> Result<Vec<Class>, Error<Rule>> {
1519
let example: Pair<Rule> = ExampleParser::parse(Rule::Program, file)?.next().unwrap();
1620

1721
if example.as_rule() != Rule::Program {
@@ -53,7 +57,7 @@ fn next_id(inners: &mut Pairs<Rule>) -> String {
5357
// calling to_string() immediately would return "Identifier(<location>)",
5458
// while as_str() returns the actual str-slice captured by the Identifier-rule
5559
// We still have to copy that str-slice into its own string object with to_string() though
56-
inners.next().unwrap().as_str().to_string()
60+
inners.next().unwrap().as_str().trim().to_string()
5761
}
5862

5963
fn parse_method(pair: Pair<Rule>) -> MethodDecl {
@@ -142,33 +146,31 @@ fn parse_field(pair: Pair<Rule>) -> Vec<FieldDecl> {
142146
match pair.as_rule() {
143147
Rule::FieldDecl => {
144148
let mut inners = pair.into_inner();
145-
let JType = parse_Type(inners.next().unwrap());
146-
let varDecels = inners.next().unwrap().into_inner();
147-
148-
varDecels
149-
.map(|x| {
150-
let mut inner = x.into_inner();
151-
let other_name = next_id(&mut inner);
152-
match inner.next() {
153-
None => FieldDecl {
154-
field_type: JType.clone(),
155-
name: other_name,
156-
val: None,
157-
},
158-
Some(val) => FieldDecl {
159-
field_type: JType.clone(),
160-
name: other_name,
161-
val: Some(parse_expr(val)),
162-
},
163-
}
164-
})
165-
.collect()
149+
let jtype = parse_Type(inners.next().unwrap());
150+
parse_field_var_decl_list(jtype, inners.next().unwrap())
166151
}
167152

168153
_ => unreachable!(),
169154
}
170155
}
171156

157+
fn parse_field_var_decl_list(jtype: Type, pair: Pair<Rule>) -> Vec<FieldDecl> {
158+
assert_eq!(pair.as_rule(), Rule::FieldVarDeclList);
159+
let mut inners = pair.into_inner();
160+
let mut var_decl = inners.next().unwrap().into_inner();
161+
let name = next_id(&mut var_decl);
162+
let val = var_decl.next().and_then(|expr| Some(parse_expr(expr)));
163+
let mut out = vec![FieldDecl {
164+
field_type: jtype.clone(),
165+
name,
166+
val,
167+
}];
168+
if let Some(p) = inners.next() {
169+
out.append(&mut parse_field_var_decl_list(jtype, p));
170+
}
171+
return out;
172+
}
173+
172174
fn parse_Type(pair: Pair<Rule>) -> Type {
173175
match pair.as_rule() {
174176
Rule::JType => parse_Type(pair.into_inner().next().unwrap()),
@@ -185,9 +187,26 @@ fn parse_Type(pair: Pair<Rule>) -> Type {
185187
_ => unreachable!(),
186188
}
187189
}
190+
188191
fn parse_expr(pair: Pair<Rule>) -> Expr {
189-
todo!()
192+
println!("{:?}", pair);
193+
match pair.as_rule() {
194+
Rule::Expr => parse_expr(pair.into_inner().next().unwrap()),
195+
Rule::NonBinaryExpr => parse_expr(pair.into_inner().next().unwrap()),
196+
Rule::IntLiteral => Expr::Integer(pair.as_str().parse().unwrap()),
197+
Rule::BoolLiteral => Expr::Bool(pair.as_str().parse().unwrap()),
198+
Rule::CharLiteral => Expr::Char(get_str_content(pair.as_str()).parse().unwrap()),
199+
Rule::StrLiteral => Expr::String(get_str_content(pair.as_str()).to_string()),
200+
Rule::JNull => Expr::Jnull,
201+
Rule::ThisExpr => Expr::This,
202+
_ => todo!(),
203+
}
190204
}
205+
206+
fn get_str_content(s: &str) -> &str {
207+
&s[1..s.len() - 1]
208+
}
209+
191210
fn parse_value(pair: Pair<Rule>) -> Expr {
192211
match pair.as_rule() {
193212
// Rule::ID => Example::ID(String::from(pair.as_str())),

lib/src/parser/test.rs

-8
This file was deleted.

0 commit comments

Comments
 (0)