tsar 0.3.0

Tsar programming language
Documentation

use crate::assembler::{
    lower::Lower,
    tokens::{ClassDef, Module, Program, Assignment, Identifier, Value, List, FirstValue, SecondValue, Literal, IndexedName, DotName, Call, Number, Math, ScopedName, Function, Expr, FunctionDef, Import}
};

use lalrpop_util::ParseError;

grammar;


extern {
    type Location = usize;
    type Error = String;
}


pub Str: String = <s:r#""(\\.|[^"])*""#> => String::from(&s[1..s.len()-1]);

pub Num: String = {
    r"([0-9]+([.][0-9]*)?|[.][0-9]+)" => <>.to_string(),
}

pub Program: Program = {
    <imports: (<Import> ";")*> <modules: (<Module> ";")*> <body: Body> => Program(imports, modules, body)
}

pub Body: Vec<Expr> = {
    <first: Expr*> <last: Value?> => {
        let mut result = first;
        if let Some(val) = last {
            result.push(Expr::Value(val));
        }
        result
    }
}

pub Module: Module = {
    "mod" <module: ScopedName> => {
        Module(module)
    },
    "mod" <ident: Ident> => {
        let Identifier(name) = ident;
        Module(ScopedName(vec![name]))
    }
}

pub Import: Import = {
    "use" <import: ScopedName> => {
        let ScopedName(names) = import;
        let module = ScopedName(names[..names.len()-1].to_vec());
        let import_name = names[names.len()-1].clone();
        Import {
            module,
            imports: vec![import_name]
        }
    },
    "use" <module: Ident> "::" <import_names: List<"{", Ident, ",", "}">> => {
        let Identifier(module_name) = module;
        let imports = import_names.iter().map(|i| {
            let Identifier(s) = i;
            s.to_string()
        }).collect::<Vec<String>>();
        
        Import {
            module: ScopedName(vec![module_name]),
            imports
        }
    },
    "use" <module: ScopedName> "::" <import_names: List<"{", Ident, ",", "}">> => {
        let imports = import_names.iter().map(|i| {
            let Identifier(s) = i;
            s.to_string()
        }).collect::<Vec<String>>();

        Import {
            module,
            imports
        }
    }
}

pub Op: String = {
    "*" => String::from("*"),
    "/" => String::from("/"),
    "%" => String::from("%"),
    "+" => String::from("+"),
    "-" => String::from("-"),
    "is" => String::from("is"),
    "isnt" => String::from("isnt"),
}

pub Ident: Identifier = {
    r"[a-zA-Z_][a-zA-Z0-9_]*" => Identifier(<>.to_string())
}

pub Expr: Expr = {
    FunctionDef => Expr::FunctionDef(<>),
    ClassDef => Expr::ClassDef(<>),
    IfStatement => <>,
    WhileLoop => <>,
    ForLoop => <>,
    <v:Value> ";" => Expr::Value(v),
    <name:Value> "=" <val:Value> ";" =>? {
        let convert_to_indexed_name = |head, tail_list: Vec<SecondValue>| -> Result<Value, ()> {
            if let FirstValue::Identifier(_) = head {
                if tail_list.is_empty() { return Ok(Value(head, vec![])); }

                let mut tail_result = vec![];
                for name in &tail_list {
                    match name {
                        SecondValue::IndexedName(n) => tail_result.push(name.clone()),
                        SecondValue::DotName(DotName(n)) => tail_result.push(SecondValue::IndexedName(IndexedName(Literal::String(n.to_string()).lower()))),
                        otherwise => return Err(())
                    }
                }
                return Ok(Value(head, tail_result)); 
            } else if let FirstValue::ScopedName(_) = head {
                return Ok(Value(head, vec![]));
            }
            return Err(());
        };

        let Value(head, tail_list) = name.clone();
        match convert_to_indexed_name(head, tail_list) {
            Ok(n) => Ok(Expr::Assignment(Assignment(n, val))),
            Err(_) => Err(ParseError::User { error: format!("Assignment to invalid name '{}'", name.lower()) })
        }
    },
}


pub ForLoop: Expr = {
    "for" <counter:Ident> "," <element:Ident> "in" <list:Value> "{" <body:Body> "}" =>? {
        if element.lower() != counter.lower() {
            Ok(Expr::ForLoop{<>})
        } else {
            Err(ParseError::User { error: format!("Index variable '{}' and element variable '{}' are the same", counter.lower(), element.lower()) })
        }
    }
}

pub WhileLoop: Expr = {
    "while" <condition:Value> "{" <body:Body> "}" => Expr::WhileLoop(<>)
}

pub IfStatement: Expr = {
    "if" <condition:Value> "{" <then_body:Body> "}" <else_clause:("else" "{" <Body> "}")?> => {
        match else_clause {
            Some(clause) => {
                Expr::IfStatement(condition, then_body, clause)
            }
            None => {
                Expr::IfStatement(condition, then_body, vec![])
            }
        }
    }
}

pub ClassDef: ClassDef = {
    "impl" <name: StaticName> "{" <defs: FunctionDef*> "}" => {
        ClassDef(name, defs)
    }
}


pub Value: Value = {
    <val:(HeadValue TailValue*)> <tail:(<Op> <HeadValue> <TailValue*>)*> => {
        if tail.is_empty() {
            Value(val.0, val.1)
        } else {
            let mut tail = tail;

            let to_value = |math| Value(FirstValue::Math(math), vec![]);
            let add = |a, b: &Value| to_value(Math::Add(Box::new(a), Box::new(b.clone())));
            let sub = |a, b: &Value| to_value(Math::Subtract(Box::new(a), Box::new(b.clone())));
            let mul = |a, b: &Value| to_value(Math::Multiply(Box::new(a), Box::new(b.clone())));
            let rem = |a, b: &Value| to_value(Math::Remainder(Box::new(a), Box::new(b.clone())));
            let div = |a, b: &Value| to_value(Math::Divide(Box::new(a), Box::new(b.clone())));
            let is = |a, b: &Value| to_value(Math::Is(Box::new(a), Box::new(b.clone())));
            let isnt = |a, b: &Value| to_value(Math::Isnt(Box::new(a), Box::new(b.clone())));

            let mut result = vec![Value(val.0, val.1)];
            for (_, a, b) in tail.iter() {
                result.push(Value(a.clone(), b.clone()));
            }

            let mut modifying = true;
            while modifying {
            	modifying = false;
	            for (i, (op, a, b)) in tail.iter().enumerate() {
	                match op.as_str() {
	                    "*" => {
	                        result[i] = mul(result[i].clone(), &result[i+1]);
	                        result.remove(i+1);
   	                        tail.remove(i);
	                        modifying = true; break;
	                    },
	                    "/" => {
	                        result[i] = div(result[i].clone(), &result[i+1]);
	                        result.remove(i+1);
   	                        tail.remove(i);
	                        modifying = true; break;
	                    },
	                    "%" => {
	                        result[i] = rem(result[i].clone(), &result[i+1]);
	                        result.remove(i+1);
   	                        tail.remove(i);
	                        modifying = true; break;
	                    },
	                    _ => {}
	                }
	            }
            }
            
            let mut tail: Vec<_> = tail.iter().filter(|(op, _, _)| !["*", "/", "%"].contains(&op.as_str())).collect();

            modifying = true;
			while modifying {
                modifying = false;
				for (i, (op, a, b)) in tail.iter().enumerate() {
	                match op.as_str() {
	                    "+" => {
	                        result[i] = add(result[i].clone(), &result[i+1]);
	                        result.remove(i+1);
	                        tail.remove(i);
	                        modifying = true; break;
	                    },
	                    "-" => {
	                        result[i] = sub(result[i].clone(), &result[i+1]);
	                        result.remove(i+1);
   	                        tail.remove(i);
	                        modifying = true; break;
	                    },
	                    _ => {}
	                }
				}
			}
            
            let mut tail: Vec<_> = tail.iter().filter(|(op, _, _)| !["+", "-"].contains(&op.as_str())).collect();


            modifying = true;
			while modifying {
                modifying = false;
				for (i, (op, a, b)) in tail.iter().enumerate() {
	                match op.as_str() {
	                    "isnt" => {
	                        result[i] = isnt(result[i].clone(), &result[i+1]);
	                        result.remove(i+1);
	                        tail.remove(i);
	                        modifying = true; break;
	                    },
	                    "is" => {
	                        result[i] = is(result[i].clone(), &result[i+1]);
	                        result.remove(i+1);
   	                        tail.remove(i);
	                        modifying = true; break;
	                    },
	                    _ => {}
	                }
				}
			}
            
            result[0].clone()
        }
    },
}


FunctionDef: FunctionDef = {
    "fn" <name:StaticName> <args:List<"(", Ident, ",", ")">> "=>" <e:Expr> => {
        FunctionDef(name, Function(args, vec![e]))
    },
    "fn" <name:StaticName> <args:List<"(", Ident, ",", ")">> "{" <body:Body> "}" => {
        FunctionDef(name, Function(args, body))
    },
}

Function: Function = {
    <l:List<"|", Ident, ",", "|">> "{" <body:Body> "}" => Function(l, body),
}


HeadValue: FirstValue = {
    StaticName => <>,
    Literal => FirstValue::Literal(<>),
    "(" <v:Value> ")" => FirstValue::Group(Box::new(v))
}

Literal: Literal = {
    Str => Literal::String(<>),
    Num => Literal::Number(Number(<>)),
    "@" <i:Ident> => Literal::ForeignFunction(i),
    Function => Literal::Function(<>),
    ListLiteral => Literal::List(<>),
}

ListLiteral: List = {
    List<"[", Value, ",", "]"> => List(<>)
}

TailValue: SecondValue = {
    "." <i:Ident> => {
        let Identifier(string) = i;
        SecondValue::DotName(DotName(string))
    },
    "[" <v:Value> "]" => {
        SecondValue::IndexedName(IndexedName(v.lower()))
    },
    <args: List<"(", Value, ",", ")">> => SecondValue::Call(Call(args)),
}

Infix<First, Operator, Second>: (First, Operator, Second) = {
    <first:First> <op: Operator> <second:Second> => {
        (<>)
    }
}

StaticName: FirstValue = {
    ScopedName => FirstValue::ScopedName(<>),
    Ident => FirstValue::Identifier(<>),
}

#[inline]
ScopedName: ScopedName = {
    <head: Ident> <tail:("::" <Ident>)+> => {
        let mut name = vec![];
        let Identifier(string) = head;
        name.push(string);
        for ident in tail {
            let Identifier(string) = ident;
            name.push(string);
        }
        ScopedName(name)
    }
}

List<Begin, T, Sep, End>: Vec<T> = {
    <first:Begin> <list: (<T> <Sep>)*> <end:T?> <last:End> => {
        match end {
            None => list.iter().map(|(v, s)| v.clone()).collect(),
            Some(val) => {
                let mut list: Vec<_> = list.iter().map(|(v, s)| v.clone()).collect();
                list.push(val);
                list
            }
        }
    }
}