Skip to content

Commit

Permalink
feat: implements type_analyze
Browse files Browse the repository at this point in the history
  • Loading branch information
sbwtw committed Sep 7, 2024
1 parent 313000a commit f9a1b82
Show file tree
Hide file tree
Showing 12 changed files with 139 additions and 37 deletions.
65 changes: 64 additions & 1 deletion lib/src/analysis/type_analyze.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::ast::*;
use crate::context::Scope;
use smallvec::smallvec;

/// Type analysis attribute
#[derive(Clone, Default)]
Expand Down Expand Up @@ -98,13 +99,24 @@ impl AstVisitorMut for TypeAnalyzer {

fn visit_operator_expression_mut(&mut self, expr: &mut OperatorExpression) {
// collect all operands type
let mut operands_attr = vec![];
let mut operands_attr: SmallVec3<_> = smallvec![];
for operand in expr.operands_mut() {
self.push(TypeAnalyzerAttribute::default());
self.visit_expression_mut(operand);
operands_attr.push(self.pop());
}

// Set operator result type
let op_type = match operands_attr.len() {
1 => operands_attr[0].derived_type.clone(),
2 => analyze_op_expr_type(
&operands_attr[0].derived_type,
&operands_attr[1].derived_type,
),
_ => None,
};
expr.set_ty(op_type);

// let ref mut result_type = self.top_mut().derived_type;
// for attr in operands_attr {
// if let Some(true) = attr
Expand Down Expand Up @@ -151,3 +163,54 @@ impl AstVisitorMut for TypeAnalyzer {
self.top_mut().derived_type = attr.derived_type
}
}

fn analyze_op_expr_type(op1: &Option<Type>, op2: &Option<Type>) -> Option<Type> {
let tc1 = op1.as_ref()?.type_class();
let tc2 = op2.as_ref()?.type_class();

// Usertype is not handled
if matches!(tc1, TypeClass::UserType(..)) {
return None;
}
if matches!(tc2, TypeClass::UserType(..)) {
return None;
}

// Array is not handled
if matches!(tc1, TypeClass::Array(..)) {
return None;
}
if matches!(tc2, TypeClass::Array(..)) {
return None;
}

// Same type
if tc1 == tc2 {
return op1.clone();
}

match tc1 {
// BitType can implicit convert to any type except String
TypeClass::Bit => match tc2 {
TypeClass::String => None,
_ => op2.clone(),
},

TypeClass::Bool => match tc2 {
TypeClass::Bit => op1.clone(),
_ => None,
},

TypeClass::Byte => match tc2 {
TypeClass::Bit => op1.clone(),
TypeClass::SInt | TypeClass::UInt | TypeClass::Int => op2.clone(),
_ => unimplemented!("{:?}", op2),
},

TypeClass::Int => match tc2 {
TypeClass::Byte | TypeClass::SInt | TypeClass::Bit => op1.clone(),
_ => None,
},
_ => unimplemented!("{:?}", op1),
}
}
3 changes: 2 additions & 1 deletion lib/src/ast/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub enum ExprKind {

#[derive(Debug)]
pub struct Expression {
pub kind: ExprKind,
pub(crate) kind: ExprKind,
}

impl_ast_display!(Expression, visit_expression);
Expand All @@ -37,6 +37,7 @@ impl Expression {
}

/// Get type of this expression
#[inline]
pub fn ty(&self) -> Option<&Type> {
match &self.kind {
ExprKind::Variable(var_expr) => var_expr.ty(),
Expand Down
29 changes: 29 additions & 0 deletions lib/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use bitflags::bitflags;
use smallvec::SmallVec;
use std::cell::RefCell;
use std::fmt::{self, Debug, Display, Formatter};
use std::hash::{Hash, Hasher};
use std::rc::Rc;

use crate::parser::{LiteralValue, Operator, StString};
Expand Down Expand Up @@ -321,6 +322,34 @@ pub enum TypeClass {
Array(RefCell<ArrayType>),
}

impl Hash for TypeClass {
fn hash<H: Hasher>(&self, state: &mut H) {
let tag = match self {
TypeClass::Bit => 1,
TypeClass::Bool => 2,
TypeClass::Byte => 3,
TypeClass::UInt => 4,
TypeClass::Int => 5,
_ => unimplemented!("{:?}", self),
};

tag.hash(state);

// TODO: incomplete implements
match self {
TypeClass::UserType(user_type) => {
user_type.borrow().name().hash(state);
}
TypeClass::Array(array_type) => {
let array_type = array_type.borrow();
let base_type = array_type.base_type().borrow();
base_type.type_class().hash(state);
}
_ => {}
}
}
}

impl Display for TypeClass {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Expand Down
7 changes: 6 additions & 1 deletion lib/src/ast/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ impl ArrayType {
dimensions,
}
}

#[inline]
pub fn base_type(&self) -> &RefCell<Type> {
&self.base_type
}
}

impl Display for ArrayType {
Expand Down Expand Up @@ -219,4 +224,4 @@ impl From<ArrayType> for Type {

Type::from_class(class)
}
}
}
9 changes: 1 addition & 8 deletions lib/src/ast/visitor.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
#![allow(dead_code)]

use crate::ast::call_expression::CallExpression;
use crate::ast::{
AliasDeclare, AssignExpression, CompoAccessExpression, DeclKind, Declaration, EnumDeclare,
ExprKind, ExprStatement, Expression, FunctionDeclare, GlobalVariableDeclare, IfStatement,
LiteralExpression, OperatorExpression, Statement, StmtKind, StructDeclare, Variable,
VariableExpression,
};
use crate::ast::*;

use super::RangeExpression;

Expand Down
9 changes: 9 additions & 0 deletions lib/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ pub use operator::Operator;
mod token;
pub use token::TokenKind;

#[macro_export]
macro_rules! parse_statement {
($code: literal) => {{
let mut lexer = StLexerBuilder::new().build_str($code);
let parser = ParserBuilder::default().build();
parser.parse_stmt(&mut lexer)
}};
}

#[cfg(test)]
mod test;

Expand Down
2 changes: 1 addition & 1 deletion lib/src/serde/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
mod xml;
pub use xml::Application;
pub use xml::Project;
20 changes: 10 additions & 10 deletions lib/src/serde/xml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,38 @@ use std::str::FromStr;
use uuid::Uuid;

#[derive(Serialize, Deserialize, Debug)]
pub enum AppType {
pub enum ProjectType {
App,
Library,
}

impl Default for AppType {
impl Default for ProjectType {
fn default() -> Self {
Self::App
}
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Application {
pub struct Project {
#[serde(default, rename = "pou-list")]
pub pou_list: POUList,
#[serde(rename = "@name")]
pub name: String,
#[serde(rename = "@type", default)]
pub app_type: AppType,
pub project_type: ProjectType,
#[serde(rename = "@namespace")]
pub namespace: Option<String>,
}

impl From<Application> for ModuleContext {
fn from(app: Application) -> Self {
let ctx = match app.app_type {
AppType::App => ModuleContext::new(ModuleKind::Application),
AppType::Library => ModuleContext::new(ModuleKind::Library),
impl From<Project> for ModuleContext {
fn from(proj: Project) -> Self {
let ctx = match proj.project_type {
ProjectType::App => ModuleContext::new(ModuleKind::Application),
ProjectType::Library => ModuleContext::new(ModuleKind::Library),
};
let mut ctx_write = ctx.write();

for pou in app.pou_list.pou {
for pou in proj.pou_list.pou {
let mut lexer = StLexerBuilder::new().build_str(&pou.interface.content);
let decl = ParserBuilder::default().build().parse(&mut lexer).unwrap();
let func = ctx_write.add_declaration(
Expand Down
17 changes: 7 additions & 10 deletions lib/src/test/test_type_analyze.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
use crate::analysis::TypeAnalyzer;
use crate::parse_statement;
use crate::parser::{ParserBuilder, StLexerBuilder};
use crate::prelude::*;
use crate::serde::Application;

use crate::analysis::TypeAnalyzer;
use crate::serde::Project;
use quick_xml::de::from_str;

#[test]
fn test_type_analyze() {
let app: Application = from_str(include_str!("test_projects/test_proj1.xml")).unwrap();
let mgr = UnitsManager::new();
let app: Project = from_str(include_str!("test_projects/test_proj1.xml")).unwrap();
let ctx: ModuleContext = app.into();

let mgr = UnitsManager::new();
let ctx_id = ctx.read().id();
mgr.write().add_context(ctx.clone());
mgr.write().set_active_application(Some(ctx.read().id()));

let stmt_str = "c := a + b;";
let mut lexer = StLexerBuilder::new().build_str(stmt_str);
let parser = ParserBuilder::default().build();
let mut stmt = parser.parse_stmt(&mut lexer).unwrap();

let mut stmt = parse_statement!("c := a + b;").unwrap();
let mut type_analyzer = TypeAnalyzer::new();
type_analyzer.analyze_statement(&mut stmt, mgr.module_scope(ctx_id));

Expand Down
11 changes: 8 additions & 3 deletions lib/src/utils/hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ impl MyHash for Variable {

impl MyHash for Type {
fn hash<H: Hasher>(&self, state: &mut H) {
todo!()
// TODO: incomplete implements
self.type_class().hash(state);
}
}

Expand Down Expand Up @@ -115,12 +116,16 @@ impl<H: Hasher> DeclVisitor<'_> for AstHasher<H> {
impl<H: Hasher> AstVisitor<'_> for AstHasher<H> {
fn visit_literal(&mut self, literal: &LiteralExpression) {
VisitType::Literal.hash(&mut self.hasher);
literal.literal().hash(&mut self.hasher)
literal.literal().hash(&mut self.hasher);
literal.literal().ty().hash(&mut self.hasher);
}

fn visit_variable_expression(&mut self, variable: &'_ VariableExpression) {
VisitType::Variable.hash(&mut self.hasher);
variable.name().hash(&mut self.hasher)
variable.name().hash(&mut self.hasher);
if let Some(ty) = variable.ty() {
ty.hash(&mut self.hasher);
}
}

fn visit_expr_statement(&mut self, stmt: &ExprStatement) {
Expand Down
Binary file modified screenshots/Screenshot_20231209_230838.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions viewer/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use stc::analysis::TypeAnalyzer;
use stc::backend::{CodeGenBackend, CodeGenDriver, LuaBackend};
use stc::prelude::*;
use stc::serde::Application;
use stc::serde::Project;
use stc::utils::write_ast_to_file;

use log::info;
Expand All @@ -21,7 +21,7 @@ impl StcViewerApp {
}

#[inline]
pub fn from_app(app: Application) -> Self {
pub fn from_app(app: Project) -> Self {
let mgr = UnitsManager::new();
let ctx: ModuleContext = app.into();
mgr.write().add_context(ctx.clone());
Expand Down

0 comments on commit f9a1b82

Please sign in to comment.