Browse Source

Resolve yul literals (#687)

Signed-off-by: Lucas Steuernagel <lucas.tnagel@gmail.com>
Lucas Steuernagel 3 years ago
parent
commit
afc93afb84

+ 1 - 0
Cargo.toml

@@ -44,6 +44,7 @@ indexmap = "1.8"
 once_cell = "1.9"
 solang-parser = { path = "solang-parser", version = "0.1.2" }
 codespan-reporting = "0.11"
+phf = "0.10.1"
 
 [dev-dependencies]
 num-derive = "0.3"

+ 3 - 4
solang-parser/src/pt.rs

@@ -668,26 +668,25 @@ pub enum AssemblyExpression {
     BoolLiteral(Loc, bool, Option<Identifier>),
     NumberLiteral(Loc, BigInt, Option<Identifier>),
     HexNumberLiteral(Loc, String, Option<Identifier>),
+    HexStringLiteral(HexLiteral, Option<Identifier>),
     StringLiteral(StringLiteral, Option<Identifier>),
     Variable(Identifier),
     Assign(Loc, Box<AssemblyExpression>, Box<AssemblyExpression>),
-    LetAssign(Loc, Box<AssemblyExpression>, Box<AssemblyExpression>),
     FunctionCall(Box<AssemblyFunctionCall>),
     Member(Loc, Box<AssemblyExpression>, Identifier),
-    Subscript(Loc, Box<AssemblyExpression>, Box<AssemblyExpression>),
 }
 
 #[derive(Debug, PartialEq, Clone)]
 pub struct AssemblyTypedIdentifier {
     pub loc: Loc,
-    pub name: Identifier,
+    pub id: Identifier,
     pub ty: Option<Identifier>,
 }
 
 #[derive(Debug, PartialEq, Clone)]
 pub struct AssemblyFunctionDefinition {
     pub loc: Loc,
-    pub name: Identifier,
+    pub id: Identifier,
     pub params: Vec<AssemblyTypedIdentifier>,
     pub returns: Vec<AssemblyTypedIdentifier>,
     pub body: Vec<AssemblyStatement>,

+ 10 - 4
solang-parser/src/solidity.lalrpop

@@ -834,6 +834,12 @@ AssemblyLiteral: AssemblyExpression = {
     <l:@L> <n:hexnumber> <t_type:(":" <AssemblyIdentifier>)?> <r:@R> => {
         AssemblyExpression::HexNumberLiteral(Loc::File(file_no, l, r), n.to_owned(), t_type)
     },
+    <l:@L> <s:hexstring> <t_type:(":" <AssemblyIdentifier>)?> <r:@R> => {
+        let v = s.to_string();
+        let hex_len = v.len() - 5;
+        AssemblyExpression::HexStringLiteral(HexLiteral{ loc: Loc::File(file_no, l, r), hex: v.chars().skip(4).filter(|c| *c != '_' && *c != '"' && *c != '\'').collect()},
+        t_type)
+    },
     <str:StringLiteral> <t_type:(":" <AssemblyIdentifier>)?> => {
         AssemblyExpression::StringLiteral(str, t_type)
     },
@@ -866,7 +872,7 @@ AssemblyFunctionDefinition: AssemblyStatement = {
         };
         AssemblyStatement::FunctionDefinition(Box::new(AssemblyFunctionDefinition{
             loc: Loc::File(file_no, l, r),
-            name,
+            id: name,
             params,
             returns,
             body
@@ -885,10 +891,10 @@ AssemblyType: AssemblyTypedIdentifier = {
     <l:@L> <var_name:AssemblyIdentifier> ":" <var_type:AssemblyIdentifier> <r:@R> =>
        AssemblyTypedIdentifier{
             loc: Loc::File(file_no, l, r),
-            name: var_name, ty: Some(var_type)
+            id: var_name, ty: Some(var_type)
        },
-    <l:@L> <var_name:AssemblyIdentifier> <r:@R> =>
-       AssemblyTypedIdentifier{loc: Loc::File(file_no, l, r), name: var_name, ty: None},
+    <l:@L> <id:AssemblyIdentifier> <r:@R> =>
+       AssemblyTypedIdentifier{loc: Loc::File(file_no, l, r), id, ty: None},
 }
 
 AssemblySwitch: AssemblyStatement = {

+ 11 - 11
solang-parser/src/test.rs

@@ -656,7 +656,7 @@ fn test_assembly_parser() {
                                 Loc::File(0, 98, 108),
                                 vec![AssemblyTypedIdentifier {
                                     loc: Loc::File(0, 102, 103),
-                                    name: Identifier {
+                                    id: Identifier {
                                         loc: Loc::File(0, 102, 103),
                                         name: "x".to_string(),
                                     },
@@ -674,7 +674,7 @@ fn test_assembly_parser() {
                                     Loc::File(0, 139, 149),
                                     vec![AssemblyTypedIdentifier {
                                         loc: Loc::File(0, 143, 144),
-                                        name: Identifier {
+                                        id: Identifier {
                                             loc: Loc::File(0, 143, 144),
                                             name: "i".to_string(),
                                         },
@@ -802,7 +802,7 @@ fn test_assembly_parser() {
                                 vec![
                                     AssemblyTypedIdentifier {
                                         loc: Loc::File(0, 418, 425),
-                                        name: Identifier {
+                                        id: Identifier {
                                             loc: Loc::File(0, 418, 419),
                                             name: "h".to_string(),
                                         },
@@ -813,7 +813,7 @@ fn test_assembly_parser() {
                                     },
                                     AssemblyTypedIdentifier {
                                         loc: Loc::File(0, 427, 428),
-                                        name: Identifier {
+                                        id: Identifier {
                                             loc: Loc::File(0, 427, 428),
                                             name: "y".to_string(),
                                         },
@@ -821,7 +821,7 @@ fn test_assembly_parser() {
                                     },
                                     AssemblyTypedIdentifier {
                                         loc: Loc::File(0, 430, 437),
-                                        name: Identifier {
+                                        id: Identifier {
                                             loc: Loc::File(0, 430, 431),
                                             name: "z".to_string(),
                                         },
@@ -891,14 +891,14 @@ fn test_assembly_parser() {
                         statements: vec![AssemblyStatement::FunctionDefinition(Box::new(
                             AssemblyFunctionDefinition {
                                 loc: Loc::File(0, 794, 1005),
-                                name: Identifier {
+                                id: Identifier {
                                     loc: Loc::File(0, 803, 808),
                                     name: "power".to_string(),
                                 },
                                 params: vec![
                                     AssemblyTypedIdentifier {
                                         loc: Loc::File(0, 809, 820),
-                                        name: Identifier {
+                                        id: Identifier {
                                             loc: Loc::File(0, 809, 813),
                                             name: "base".to_string(),
                                         },
@@ -909,7 +909,7 @@ fn test_assembly_parser() {
                                     },
                                     AssemblyTypedIdentifier {
                                         loc: Loc::File(0, 822, 830),
-                                        name: Identifier {
+                                        id: Identifier {
                                             loc: Loc::File(0, 822, 830),
                                             name: "exponent".to_string(),
                                         },
@@ -918,7 +918,7 @@ fn test_assembly_parser() {
                                 ],
                                 returns: vec![AssemblyTypedIdentifier {
                                     loc: Loc::File(0, 835, 841),
-                                    name: Identifier {
+                                    id: Identifier {
                                         loc: Loc::File(0, 835, 841),
                                         name: "result".to_string(),
                                     },
@@ -929,7 +929,7 @@ fn test_assembly_parser() {
                                         Loc::File(0, 896, 940),
                                         vec![AssemblyTypedIdentifier {
                                             loc: Loc::File(0, 900, 901),
-                                            name: Identifier {
+                                            id: Identifier {
                                                 loc: Loc::File(0, 900, 901),
                                                 name: "y".to_string(),
                                             },
@@ -988,7 +988,7 @@ fn test_assembly_parser() {
                                         Loc::File(0, 969, 979),
                                         vec![AssemblyTypedIdentifier {
                                             loc: Loc::File(0, 973, 979),
-                                            name: Identifier {
+                                            id: Identifier {
                                                 loc: Loc::File(0, 973, 979),
                                                 name: "result".to_string(),
                                             },

+ 3 - 0
src/bin/languageserver/mod.rs

@@ -326,6 +326,9 @@ impl SolangServer {
                 }
             }
             ast::Statement::Underscore(_loc) => {}
+            ast::Statement::AssemblyBlock(_) => {
+                unimplemented!("Assembly block not implemented in language server");
+            }
         }
     }
 

+ 3 - 0
src/codegen/external_functions.rs

@@ -129,6 +129,9 @@ fn check_statement(stmt: &Statement, call_list: &mut Vec<usize>) -> bool {
         | Statement::Break(_)
         | Statement::Continue(_)
         | Statement::Underscore(_) => (),
+        Statement::AssemblyBlock(_) => {
+            unimplemented!("Assembly block codegen not yet ready!");
+        }
     }
 
     true

+ 4 - 0
src/codegen/statements.rs

@@ -621,6 +621,10 @@ pub fn statement(
                 panic!("placeholder should be provided for modifiers");
             }
         }
+
+        Statement::AssemblyBlock(_) => {
+            unimplemented!("Assembly block codegen not yet ready");
+        }
     }
 }
 

+ 2 - 2
src/lib.rs

@@ -88,8 +88,8 @@ impl Target {
         }
     }
 
-    /// Size of a pointer in bytes
-    pub fn ptr_size(&self) -> usize {
+    /// Size of a pointer in bits
+    pub fn ptr_size(&self) -> u16 {
         if *self == Target::Solana {
             // Solana is BPF, which is 64 bit
             64

+ 210 - 0
src/sema/assembly/expression.rs

@@ -0,0 +1,210 @@
+use crate::ast::{Namespace, Type};
+use crate::sema::assembly::types::{get_default_type_from_identifier, get_type_from_string};
+use crate::sema::expression::unescape;
+use crate::Target;
+use num_bigint::{BigInt, Sign};
+use num_traits::Num;
+use solang_parser::diagnostics::{ErrorType, Level};
+use solang_parser::{pt, Diagnostic};
+
+#[derive(PartialEq, Debug)]
+pub enum AssemblyExpression {
+    BoolLiteral(pt::Loc, bool, Type),
+    NumberLiteral(pt::Loc, BigInt, Type),
+    StringLiteral(pt::Loc, Vec<u8>, Type),
+    Variable(pt::Loc, usize),
+}
+
+// Avoid warnings during development
+#[allow(dead_code)]
+pub(crate) fn resolve_assembly_expression(
+    expr: &pt::AssemblyExpression,
+    ns: &mut Namespace,
+) -> Result<AssemblyExpression, ()> {
+    match expr {
+        pt::AssemblyExpression::BoolLiteral(loc, value, ty) => {
+            resolve_bool_literal(loc, value, ty, ns)
+        }
+
+        pt::AssemblyExpression::NumberLiteral(loc, value, ty) => {
+            resolve_number_literal(loc, value, ty, ns)
+        }
+
+        pt::AssemblyExpression::HexNumberLiteral(loc, value, ty) => {
+            resolve_hex_literal(loc, value, ty, ns)
+        }
+        pt::AssemblyExpression::HexStringLiteral(value, ty) => {
+            if (value.hex.len() % 2) != 0 {
+                ns.diagnostics.push(Diagnostic {
+                    pos: value.loc,
+                    ty: ErrorType::DeclarationError,
+                    level: Level::Error,
+                    message: format!("hex string \"{}\" has odd number of characters", value.hex),
+                    notes: vec![],
+                });
+                return Err(());
+            }
+
+            let mut byte_array: Vec<u8> = Vec::new();
+            byte_array.extend_from_slice(&hex::decode(&value.hex).unwrap());
+
+            resolve_string_literal(&value.loc, byte_array, ty, ns)
+        }
+
+        pt::AssemblyExpression::StringLiteral(value, ty) => {
+            let unescaped_string = unescape(
+                &value.string[..],
+                0,
+                value.loc.file_no(),
+                &mut ns.diagnostics,
+            );
+            resolve_string_literal(&value.loc, unescaped_string, ty, ns)
+        }
+
+        // TODO: This is a workaround to avoid compilation errors, while we don't finish resolving all expressions
+        _ => Ok(AssemblyExpression::Variable(pt::Loc::File(0, 0, 0), 0)),
+    }
+}
+
+fn get_type_from_big_int(big_int: &BigInt, target: &Target) -> Type {
+    match big_int.sign() {
+        Sign::Minus => Type::Int(target.ptr_size()),
+        _ => Type::Uint(target.ptr_size()),
+    }
+}
+
+fn resolve_bool_literal(
+    loc: &pt::Loc,
+    value: &bool,
+    ty: &Option<pt::Identifier>,
+    ns: &mut Namespace,
+) -> Result<AssemblyExpression, ()> {
+    let new_type = if let Some(type_id) = ty {
+        if let Some(asm_type) = get_type_from_string(&type_id.name) {
+            asm_type
+        } else {
+            ns.diagnostics.push(Diagnostic::error(
+                type_id.loc,
+                format!("the specified type '{}' does not exist", type_id.name),
+            ));
+            return Err(());
+        }
+    } else {
+        Type::Bool
+    };
+
+    Ok(AssemblyExpression::BoolLiteral(*loc, *value, new_type))
+}
+
+fn resolve_number_literal(
+    loc: &pt::Loc,
+    value: &BigInt,
+    ty: &Option<pt::Identifier>,
+    ns: &mut Namespace,
+) -> Result<AssemblyExpression, ()> {
+    let new_type = if let Some(type_id) = ty {
+        if let Some(asm_type) = get_type_from_string(&type_id.name) {
+            if matches!(asm_type, Type::Uint(_)) && matches!(value.sign(), Sign::Minus) {
+                ns.diagnostics.push(Diagnostic {
+                    pos: *loc,
+                    level: Level::Error,
+                    ty: ErrorType::TypeError,
+                    message: "singed value cannot fit in unsigned type".to_string(),
+                    notes: vec![],
+                });
+                return Err(());
+            }
+            asm_type
+        } else {
+            ns.diagnostics.push(Diagnostic::error(
+                type_id.loc,
+                format!("the specified type '{}' does not exist", type_id.name),
+            ));
+            return Err(());
+        }
+    } else {
+        get_type_from_big_int(value, &ns.target)
+    };
+
+    let type_size = new_type.get_type_size();
+
+    let bits_needed = match value.sign() {
+        Sign::Minus => value.bits() + 1,
+        _ => value.bits(),
+    };
+
+    if bits_needed > type_size as u64 {
+        ns.diagnostics.push(Diagnostic {
+            level: Level::Error,
+            ty: ErrorType::TypeError,
+            pos: *loc,
+            message: format!(
+                "the provided literal requires {} bits, but the type only supports {}",
+                bits_needed, type_size
+            ),
+            notes: vec![],
+        });
+    }
+
+    Ok(AssemblyExpression::NumberLiteral(
+        *loc,
+        value.clone(),
+        new_type,
+    ))
+}
+
+fn resolve_hex_literal(
+    loc: &pt::Loc,
+    value: &str,
+    ty: &Option<pt::Identifier>,
+    ns: &mut Namespace,
+) -> Result<AssemblyExpression, ()> {
+    let new_type = get_default_type_from_identifier(ty, ns)?;
+
+    let s: String = value.chars().skip(2).filter(|v| *v != '_').collect();
+    let val = BigInt::from_str_radix(&s, 16).unwrap();
+    let type_size = new_type.get_type_size();
+    if val.bits() > type_size as u64 {
+        ns.diagnostics.push(Diagnostic {
+            level: Level::Error,
+            ty: ErrorType::TypeError,
+            pos: *loc,
+            message: format!(
+                "the provided literal requires {} bits, but the type only supports {}",
+                val.bits(),
+                type_size
+            ),
+            notes: vec![],
+        });
+    }
+
+    Ok(AssemblyExpression::NumberLiteral(*loc, val, new_type))
+}
+
+fn resolve_string_literal(
+    loc: &pt::Loc,
+    byte_array: Vec<u8>,
+    ty: &Option<pt::Identifier>,
+    ns: &mut Namespace,
+) -> Result<AssemblyExpression, ()> {
+    let new_type = get_default_type_from_identifier(ty, ns)?;
+    let type_size = new_type.get_type_size();
+
+    if byte_array.len() * 8 > type_size as usize {
+        ns.diagnostics.push(Diagnostic {
+            level: Level::Error,
+            ty: ErrorType::DeclarationError,
+            pos: *loc,
+            message: format!(
+                "the provided literal requires {} bits, but the type only supports {}",
+                byte_array.len() * 8,
+                type_size
+            ),
+            notes: vec![],
+        });
+    }
+
+    Ok(AssemblyExpression::StringLiteral(
+        *loc, byte_array, new_type,
+    ))
+}

+ 23 - 0
src/sema/assembly/functions.rs

@@ -0,0 +1,23 @@
+use crate::ast::Type;
+use crate::sema::assembly::AssemblyStatement;
+use crate::sema::symtable::Symtable;
+use indexmap::IndexMap;
+use solang_parser::pt;
+
+#[derive(Debug, Clone)]
+pub struct AssemblyFunction {
+    pub loc: pt::Loc,
+    pub name: String,
+    pub params: Vec<AssemblyFunctionParameter>,
+    pub returns: Vec<AssemblyFunctionParameter>,
+    pub body: Vec<AssemblyStatement>,
+    pub functions: IndexMap<String, AssemblyFunction>,
+    pub symtable: Symtable,
+}
+
+#[derive(Debug, Clone)]
+pub struct AssemblyFunctionParameter {
+    pub loc: pt::Loc,
+    pub name: pt::Identifier,
+    pub ty: Type,
+}

+ 21 - 0
src/sema/assembly/mod.rs

@@ -0,0 +1,21 @@
+use crate::sema::assembly::functions::AssemblyFunction;
+use indexmap::IndexMap;
+use solang_parser::pt;
+
+mod expression;
+mod functions;
+mod tests;
+mod types;
+
+// TODO: Functions can be called anywhere inside the block.
+#[derive(Debug, Clone)]
+pub struct AssemblyBlock {
+    pub loc: pt::Loc,
+    pub body: Vec<AssemblyStatement>,
+    pub functions: IndexMap<String, AssemblyFunction>,
+}
+
+#[derive(Debug, Clone)]
+pub enum AssemblyStatement {
+    AssemblyBlock(AssemblyBlock),
+}

+ 206 - 0
src/sema/assembly/tests/expression.rs

@@ -0,0 +1,206 @@
+#![cfg(test)]
+use crate::ast::{Namespace, Type};
+use crate::sema::assembly::expression::{resolve_assembly_expression, AssemblyExpression};
+use crate::Target;
+use num_bigint::BigInt;
+use num_traits::FromPrimitive;
+use solang_parser::pt;
+use solang_parser::pt::{HexLiteral, Identifier, Loc, StringLiteral};
+
+#[test]
+fn resolve_bool_literal() {
+    let mut ns = Namespace::new(Target::Solana);
+    let expr = pt::AssemblyExpression::BoolLiteral(
+        Loc::File(0, 3, 5),
+        false,
+        Some(pt::Identifier {
+            loc: Loc::File(0, 3, 4),
+            name: "u32".to_string(),
+        }),
+    );
+
+    let resolved_type = resolve_assembly_expression(&expr, &mut ns);
+    assert!(resolved_type.is_ok());
+    assert!(ns.diagnostics.is_empty());
+    let unwrapped = resolved_type.unwrap();
+
+    assert_eq!(
+        unwrapped,
+        AssemblyExpression::BoolLiteral(Loc::File(0, 3, 5), false, Type::Uint(32))
+    );
+
+    let expr = pt::AssemblyExpression::BoolLiteral(Loc::File(0, 3, 5), true, None);
+    let resolved_type = resolve_assembly_expression(&expr, &mut ns);
+
+    assert!(resolved_type.is_ok());
+    assert!(ns.diagnostics.is_empty());
+    let unwrapped = resolved_type.unwrap();
+    assert_eq!(
+        unwrapped,
+        AssemblyExpression::BoolLiteral(Loc::File(0, 3, 5), true, Type::Bool)
+    );
+}
+
+#[test]
+fn resolve_number_literal() {
+    let loc = Loc::File(0, 3, 5);
+    let mut ns = Namespace::new(Target::Solana);
+    let expr = pt::AssemblyExpression::NumberLiteral(
+        loc,
+        BigInt::from_u128(0xffffffffffffffffff).unwrap(),
+        None,
+    );
+    let parsed = resolve_assembly_expression(&expr, &mut ns);
+    assert!(parsed.is_ok());
+    assert_eq!(ns.diagnostics.len(), 1);
+    assert_eq!(
+        ns.diagnostics[0].message,
+        "the provided literal requires 72 bits, but the type only supports 64"
+    );
+
+    ns.diagnostics.clear();
+    let expr = pt::AssemblyExpression::NumberLiteral(
+        loc,
+        BigInt::from_i32(-50).unwrap(),
+        Some(Identifier {
+            loc,
+            name: "u128".to_string(),
+        }),
+    );
+    let parsed = resolve_assembly_expression(&expr, &mut ns);
+    assert!(parsed.is_err());
+    assert_eq!(ns.diagnostics.len(), 1);
+    assert_eq!(
+        ns.diagnostics[0].message,
+        "singed value cannot fit in unsigned type"
+    );
+
+    ns.diagnostics.clear();
+    let expr = pt::AssemblyExpression::NumberLiteral(loc, BigInt::from(20), None);
+    let parsed = resolve_assembly_expression(&expr, &mut ns);
+    assert!(parsed.is_ok());
+    assert!(ns.diagnostics.is_empty());
+    assert_eq!(
+        parsed.unwrap(),
+        AssemblyExpression::NumberLiteral(loc, BigInt::from(20), Type::Uint(64))
+    );
+}
+
+#[test]
+fn resolve_hex_number_literal() {
+    let mut ns = Namespace::new(Target::Ewasm);
+    let loc = Loc::File(0, 3, 5);
+    let expr = pt::AssemblyExpression::HexNumberLiteral(loc, "0xf23456789a".to_string(), None);
+
+    let resolved = resolve_assembly_expression(&expr, &mut ns);
+    assert!(resolved.is_ok());
+    assert_eq!(ns.diagnostics.len(), 1);
+    assert_eq!(
+        ns.diagnostics[0].message,
+        "the provided literal requires 40 bits, but the type only supports 32"
+    );
+
+    ns.diagnostics.clear();
+    let expr = pt::AssemblyExpression::HexNumberLiteral(
+        loc,
+        "0xff".to_string(),
+        Some(Identifier {
+            loc,
+            name: "s64".to_string(),
+        }),
+    );
+    let resolved = resolve_assembly_expression(&expr, &mut ns);
+    assert!(resolved.is_ok());
+    assert!(ns.diagnostics.is_empty());
+    assert_eq!(
+        resolved.unwrap(),
+        AssemblyExpression::NumberLiteral(loc, BigInt::from(255), Type::Int(64))
+    );
+}
+
+#[test]
+fn resolve_hex_string_literal() {
+    let mut ns = Namespace::new(Target::Ewasm);
+    let loc = Loc::File(0, 3, 5);
+    let expr = pt::AssemblyExpression::HexStringLiteral(
+        HexLiteral {
+            loc,
+            hex: "3ca".to_string(),
+        },
+        None,
+    );
+
+    let resolved = resolve_assembly_expression(&expr, &mut ns);
+    assert!(resolved.is_err());
+    assert_eq!(ns.diagnostics.len(), 1);
+    assert_eq!(
+        ns.diagnostics[0].message,
+        "hex string \"3ca\" has odd number of characters"
+    );
+
+    ns.diagnostics.clear();
+    let expr = pt::AssemblyExpression::HexStringLiteral(
+        HexLiteral {
+            loc,
+            hex: "acdf".to_string(),
+        },
+        Some(Identifier {
+            loc,
+            name: "myType".to_string(),
+        }),
+    );
+    let resolved = resolve_assembly_expression(&expr, &mut ns);
+    assert!(resolved.is_err());
+    assert_eq!(ns.diagnostics.len(), 1);
+    assert_eq!(
+        ns.diagnostics[0].message,
+        "the specified type 'myType' does not exist"
+    );
+
+    ns.diagnostics.clear();
+    let expr = pt::AssemblyExpression::HexStringLiteral(
+        HexLiteral {
+            loc,
+            hex: "ffff".to_string(),
+        },
+        Some(Identifier {
+            loc,
+            name: "u256".to_string(),
+        }),
+    );
+    let resolved = resolve_assembly_expression(&expr, &mut ns);
+    assert!(resolved.is_ok());
+    assert!(ns.diagnostics.is_empty());
+    assert_eq!(
+        resolved.unwrap(),
+        AssemblyExpression::StringLiteral(loc, vec![255, 255], Type::Uint(256))
+    );
+}
+
+#[test]
+fn resolve_string_literal() {
+    let mut ns = Namespace::new(Target::Solana);
+    let loc = Loc::File(0, 3, 5);
+    let expr = pt::AssemblyExpression::StringLiteral(
+        StringLiteral {
+            loc,
+            string: r#"ab\xffa\u00e0g"#.to_string(),
+        },
+        Some(Identifier {
+            loc,
+            name: "u128".to_string(),
+        }),
+    );
+
+    let resolved = resolve_assembly_expression(&expr, &mut ns);
+    assert!(resolved.is_ok());
+    assert!(ns.diagnostics.is_empty());
+    assert_eq!(
+        resolved.unwrap(),
+        AssemblyExpression::StringLiteral(
+            loc,
+            vec![97, 98, 255, 97, 0xc3, 0xa0, 103],
+            Type::Uint(128)
+        )
+    );
+}

+ 2 - 0
src/sema/assembly/tests/mod.rs

@@ -0,0 +1,2 @@
+//#![assembly(test)]
+mod expression;

+ 39 - 0
src/sema/assembly/types.rs

@@ -0,0 +1,39 @@
+use crate::ast::{Namespace, Type};
+use solang_parser::pt::Identifier;
+use solang_parser::Diagnostic;
+
+pub(crate) fn get_type_from_string(text: &str) -> Option<Type> {
+    match text {
+        "bool" => Some(Type::Bool),
+        "s8" => Some(Type::Int(8)),
+        "s32" => Some(Type::Int(32)),
+        "s64" => Some(Type::Int(64)),
+        "s128" => Some(Type::Int(128)),
+        "s256" => Some(Type::Int(256)),
+        "u8" => Some(Type::Uint(8)),
+        "u32" => Some(Type::Uint(32)),
+        "u64" => Some(Type::Uint(64)),
+        "u128" => Some(Type::Uint(128)),
+        "u256" => Some(Type::Uint(256)),
+        _ => None,
+    }
+}
+
+pub(crate) fn get_default_type_from_identifier(
+    ty: &Option<Identifier>,
+    ns: &mut Namespace,
+) -> Result<Type, ()> {
+    if let Some(type_id) = ty {
+        if let Some(asm_type) = get_type_from_string(&type_id.name) {
+            Ok(asm_type)
+        } else {
+            ns.diagnostics.push(Diagnostic::error(
+                type_id.loc,
+                format!("the specified type '{}' does not exist", type_id.name),
+            ));
+            Err(())
+        }
+    } else {
+        Ok(Type::Uint(ns.target.ptr_size()))
+    }
+}

+ 13 - 0
src/sema/ast.rs

@@ -2,6 +2,7 @@ use super::symtable::Symtable;
 use crate::codegen::cfg::ControlFlowGraph;
 pub use crate::parser::diagnostics::*;
 use crate::parser::pt;
+use crate::sema::assembly::AssemblyStatement;
 use crate::Target;
 use num_bigint::BigInt;
 use num_rational::BigRational;
@@ -48,6 +49,16 @@ pub enum Type {
     Slice,
 }
 
+impl Type {
+    pub fn get_type_size(&self) -> u16 {
+        match self {
+            Type::Int(n) | Type::Uint(n) => *n,
+            Type::Bool => 1,
+            _ => unimplemented!("size of type not known"),
+        }
+    }
+}
+
 #[derive(PartialEq, Clone, Debug, Copy)]
 pub enum BuiltinStruct {
     None,
@@ -1406,6 +1417,7 @@ pub enum Statement {
     },
     TryCatch(pt::Loc, bool, TryCatch),
     Underscore(pt::Loc),
+    AssemblyBlock(Vec<AssemblyStatement>),
 }
 
 #[derive(Clone, Debug)]
@@ -1520,6 +1532,7 @@ impl Statement {
             Statement::Delete(..) => true,
             Statement::Continue(_) | Statement::Break(_) | Statement::Return(..) => false,
             Statement::For { reachable, .. } | Statement::TryCatch(_, reachable, _) => *reachable,
+            Statement::AssemblyBlock(_) => unimplemented!("Assembly block ast not ready"),
         }
     }
 }

+ 4 - 0
src/sema/dotgraphviz.rs

@@ -1561,6 +1561,10 @@ impl Dot {
                         Some(parent_rel),
                     );
                 }
+
+                Statement::AssemblyBlock(_) => {
+                    unimplemented!("Assembly block graphviz not ready yet");
+                }
             }
             parent_rel = String::from("next");
         }

+ 1 - 0
src/sema/mod.rs

@@ -7,6 +7,7 @@ use num_traits::Zero;
 use std::{collections::HashMap, ffi::OsStr};
 
 mod address;
+mod assembly;
 pub mod ast;
 pub mod builtin;
 pub mod contracts;

+ 3 - 0
src/sema/mutability.rs

@@ -215,6 +215,9 @@ fn recurse_statements(stmts: &[Statement], state: &mut StateCheck) {
             }
             Statement::Emit { loc, .. } => state.write(loc),
             Statement::Break(_) | Statement::Continue(_) | Statement::Underscore(_) => (),
+            Statement::AssemblyBlock(_) => {
+                unimplemented!("Assembly block mutability not ready yet");
+            }
         }
     }
 }

+ 1 - 0
src/sema/printer.rs

@@ -670,6 +670,7 @@ fn print_statement(stmts: &[Statement], func: &Function, ns: &Namespace) -> Vec<
                 Tree::Branch(String::from("try-catch"), list)
             }
             Statement::Underscore(_) => Tree::Leaf(String::from("underscore")),
+            Statement::AssemblyBlock(_) => unimplemented!("Assembly block printer not ready yet"),
         });
     }
 

+ 1 - 0
src/sema/statements.rs

@@ -793,6 +793,7 @@ fn statement(
             ));
             Err(())
         }
+
         pt::Statement::DocComment(..) => Ok(true),
     }
 }

+ 4 - 3
src/sema/symtable.rs

@@ -6,7 +6,7 @@ use super::ast::{Diagnostic, Namespace, Type};
 use crate::parser::pt;
 use crate::sema::ast::Expression;
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct Variable {
     pub id: pt::Identifier,
     pub ty: Type,
@@ -44,7 +44,7 @@ impl Variable {
     }
 }
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub enum VariableUsage {
     Parameter,
     ReturnVariable,
@@ -56,9 +56,10 @@ pub enum VariableUsage {
     TryCatchErrorBytes,
 }
 
+#[derive(Debug, Clone)]
 struct VarScope(HashMap<String, usize>, Option<HashSet<usize>>);
 
-#[derive(Default)]
+#[derive(Default, Debug, Clone)]
 pub struct Symtable {
     pub vars: IndexMap<usize, Variable>,
     names: LinkedList<VarScope>,

+ 1 - 1
src/sema/types.rs

@@ -901,7 +901,7 @@ impl Type {
                 .map(|f| f.ty.align_of(ns))
                 .max()
                 .unwrap(),
-            Type::InternalFunction { .. } => ns.target.ptr_size(),
+            Type::InternalFunction { .. } => ns.target.ptr_size().into(),
             _ => 1,
         }
     }