diff --git a/Cargo.lock b/Cargo.lock index 1acf8ff..4de7a38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.44" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" +checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" [[package]] name = "ariadne" @@ -83,9 +83,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" dependencies = [ "cfg-if", "libc", @@ -106,9 +106,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.105" +version = "0.2.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" [[package]] name = "pico-args" diff --git a/src/ast.rs b/src/ast.rs index fbc0658..17374f5 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,6 +1,6 @@ use std::{fmt, path::PathBuf}; -use crate::Span; +use crate::parser::Span; #[derive(Debug)] pub struct Script { diff --git a/src/lib.rs b/src/lib.rs index 39d9e59..24912f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ use anyhow::{bail, Result}; use std::ffi::OsStr; -use std::io::prelude::*; -use std::{fs::File, path::Path}; +use std::path::Path; +use parser::Sources; mod ast; mod constfold; @@ -11,8 +11,6 @@ mod intrinsics; mod parser; mod typecheck; -type Span = std::ops::Range; - #[derive(Default)] pub struct Options { pub(crate) debug: bool, @@ -26,14 +24,11 @@ impl Options { pub fn compile_file>(path: P, options: Options) -> Result> { let path = path.as_ref(); - let mut input = String::new(); - File::open(path)?.read_to_string(&mut input)?; - compile_str(&input, path, options) -} - -pub fn compile_str(input: &str, path: &Path, options: Options) -> Result> { - let mut script = match parser::parse(input) { + let mut sources = Sources::new(); + let id = sources.add(path)?; + + let mut script = match parser::parse(&sources, id) { Ok(script) => script, Err(_) => bail!("Parse failed"), }; @@ -41,7 +36,7 @@ pub fn compile_str(input: &str, path: &Path, options: Options) -> Result includes::resolve_includes(&mut script, path)?; constfold::fold_script(&mut script); - if typecheck::tc_script(&mut script, input).is_err() { + if typecheck::tc_script(&mut script, &sources).is_err() { bail!("Type check failed"); } let wasm = emit::emit( diff --git a/src/parser.rs b/src/parser.rs index d0ff1c6..f77c477 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,8 +1,62 @@ use crate::ast; -use crate::Span; -use ariadne::{Color, Fmt, Label, Report, ReportKind, Source}; -use chumsky::{prelude::*, stream::Stream}; -use std::fmt; +use anyhow::Result; +use ariadne::{Color, Fmt, Label, Report, ReportKind}; +use chumsky::prelude::*; +use std::{ + fmt, + fs::File, + io::Read, + ops::Range, + path::{Path, PathBuf}, +}; + +pub type Span = (usize, Range); + +pub struct SourceFile { + source: ariadne::Source, + path: PathBuf, +} + +pub struct Sources(Vec); + +impl Sources { + pub fn new() -> Sources { + Sources(Vec::new()) + } + + pub fn add(&mut self, path: &Path) -> Result { + let canonical = path.canonicalize()?; + for (index, source) in self.0.iter().enumerate() { + if source.path.canonicalize()? == canonical { + return Ok(index); + } + } + let mut source = String::new(); + File::open(path)?.read_to_string(&mut source)?; + self.0.push(SourceFile { + source: ariadne::Source::from(source), + path: path.to_path_buf(), + }); + Ok(self.0.len() - 1) + } +} + +impl std::ops::Index for Sources { + type Output = SourceFile; + fn index(&self, idx: usize) -> &SourceFile { + &self.0[idx] + } +} + +impl ariadne::Cache for &Sources { + fn fetch(&mut self, id: &usize) -> Result<&ariadne::Source, Box> { + Ok(&self.0[*id].source) + } + + fn display<'a>(&self, id: &'a usize) -> Option> { + Some(Box::new(self.0[*id].path.clone().display().to_string())) + } +} #[derive(Clone, Debug, PartialEq, Eq, Hash)] enum Token { @@ -61,8 +115,36 @@ impl fmt::Display for Token { } } -pub fn parse(source: &str) -> Result { - let tokens = match lexer().parse(source) { +type SourceStream = chumsky::Stream<'static, char, Span, It>; +type TokenStream = chumsky::Stream<'static, Token, Span, It>; + +pub fn parse(sources: &Sources, source_id: usize) -> Result { + let source = &sources[source_id].source; + let source_stream = SourceStream::from_iter( + (source_id, source.len()..source.len() + 1), + Box::new( + // this is a bit of an ugly hack + // once the next version of ariadne is released + // use the source string chars as input + // and only create the ariadne::Source lazily when printing errors + source + .lines() + .flat_map(|l| { + let mut chars: Vec = l.chars().collect(); + while chars.len() + 1 < l.len() { + chars.push(' '); + } + if chars.len() < l.len() { + chars.push('\n'); + } + chars.into_iter() + }) + .enumerate() + .map(|(index, char)| (char, (source_id, index..(index + 1)))), + ), + ); + + let tokens = match lexer().parse(source_stream) { Ok(tokens) => tokens, Err(errors) => { report_errors( @@ -70,15 +152,14 @@ pub fn parse(source: &str) -> Result { .into_iter() .map(|e| e.map(|c| c.to_string())) .collect(), - source, + sources, ); return Err(()); } }; - let source_len = source.chars().count(); - let script = match script_parser().parse(Stream::from_iter( - source_len..source_len + 1, + let script = match script_parser().parse(TokenStream::from_iter( + (source_id, source.len()..source.len() + 1), tokens.into_iter(), )) { Ok(script) => script, @@ -88,7 +169,7 @@ pub fn parse(source: &str) -> Result { .into_iter() .map(|e| e.map(|t| t.to_string())) .collect(), - source, + sources, ); return Err(()); } @@ -96,9 +177,9 @@ pub fn parse(source: &str) -> Result { Ok(script) } -fn report_errors(errors: Vec>, source: &str) { +fn report_errors(errors: Vec>, sources: &Sources) { for error in errors { - let report = Report::build(ReportKind::Error, (), error.span().start()); + let report = Report::build(ReportKind::Error, error.span().0, error.span().1.start()); let report = match error.reason() { chumsky::error::SimpleReason::Unclosed { span, delimiter } => report @@ -161,11 +242,12 @@ fn report_errors(errors: Vec>, source: &str) { ), }; - report.finish().eprint(Source::from(source)).unwrap(); + report.finish().eprint(sources).unwrap(); } } -fn lexer() -> impl Parser, Error = Simple> { +type LexerError = Simple; +fn lexer() -> impl Parser, Error = LexerError> { let float64 = text::int(10) .chain::(just('.').chain(text::digits(10))) .then_ignore(just("f64")) @@ -177,14 +259,14 @@ fn lexer() -> impl Parser, Error = Simple> { .collect::() .map(Token::Float); - let integer = just::<_, _, Simple>("0x") + let integer = just::<_, _, LexerError>("0x") .ignore_then(text::int(16)) .try_map(|n, span| { - u64::from_str_radix(&n, 16).map_err(|err| Simple::custom(span, err.to_string())) + u64::from_str_radix(&n, 16).map_err(|err| LexerError::custom(span, err.to_string())) }) .or(text::int(10).try_map(|n: String, span: Span| { n.parse::() - .map_err(|err| Simple::custom(span, err.to_string())) + .map_err(|err| LexerError::custom(span, err.to_string())) })) .boxed(); @@ -196,7 +278,7 @@ fn lexer() -> impl Parser, Error = Simple> { let int = integer.try_map(|n, span| { u32::try_from(n) .map(|n| Token::Int(n as i32)) - .map_err(|err| Simple::custom(span, err.to_string())) + .map_err(|err| LexerError::custom(span, err.to_string())) }); let str_ = just('"') @@ -214,7 +296,7 @@ fn lexer() -> impl Parser, Error = Simple> { let ctrl = one_of("(){};,:?!$").map(Token::Ctrl); - fn ident() -> impl Parser> + Copy + Clone { + fn ident() -> impl Parser + Copy + Clone { filter(|c: &char| c.is_ascii_alphabetic() || *c == '_') .map(Some) .chain::, _>( @@ -267,20 +349,29 @@ fn lexer() -> impl Parser, Error = Simple> { fn map_token( f: impl Fn(&Token) -> Option + 'static + Clone, -) -> impl Parser> + Clone { +) -> impl Parser + Clone { filter_map(move |span, tok: Token| { if let Some(output) = f(&tok) { Ok(output) } else { - Err(Simple::expected_input_found(span, Vec::new(), Some(tok))) + Err(ScriptError::expected_input_found( + span, + Vec::new(), + Some(tok), + )) } }) } -fn script_parser() -> impl Parser> + Clone { +type ScriptError = Simple; +fn script_parser() -> impl Parser + Clone { let identifier = filter_map(|span, tok| match tok { Token::Ident(id) => Ok(id), - _ => Err(Simple::expected_input_found(span, Vec::new(), Some(tok))), + _ => Err(ScriptError::expected_input_found( + span, + Vec::new(), + Some(tok), + )), }) .labelled("identifier"); @@ -312,7 +403,11 @@ fn script_parser() -> impl Parser> + C name: id, local_id: None, }), - _ => Err(Simple::expected_input_found(span, Vec::new(), Some(tok))), + _ => Err(ScriptError::expected_input_found( + span, + Vec::new(), + Some(tok), + )), }) .labelled("variable"); @@ -467,7 +562,7 @@ fn script_parser() -> impl Parser> + C .then(atom) .map(|(ops, value)| { ops.into_iter().rev().fold(value, |acc, (op, span)| { - let span = span.start..acc.span.end; + let span = (span.0, span.1.start..acc.span.1.end); ast::Expr::UnaryOp { op, value: Box::new(acc), @@ -507,7 +602,7 @@ fn script_parser() -> impl Parser> + C poke_op: Option<((ast::MemSize, ast::Expression), ast::Expression)>, ) -> ast::Expression { let left = peek_ops.into_iter().fold(left, |left, (size, right)| { - let span = left.span.start..right.span.end; + let span = (left.span.0, left.span.1.start..right.span.1.end); ast::Expr::Peek(ast::MemoryLocation { span: span.clone(), left: Box::new(left), @@ -517,7 +612,7 @@ fn script_parser() -> impl Parser> + C .with_span(span) }); if let Some(((size, right), value)) = poke_op { - let span = left.span.start..value.span.end; + let span = (left.span.0, left.span.1.start..value.span.1.end); ast::Expr::Poke { mem_location: ast::MemoryLocation { span: span.clone(), @@ -574,7 +669,7 @@ fn script_parser() -> impl Parser> + C .repeated(), ) .foldl(|left, (op, right)| { - let span = left.span.start..right.span.end; + let span = (left.span.0, left.span.1.start..right.span.1.end); ast::Expr::BinOp { op, left: Box::new(left), @@ -594,7 +689,7 @@ fn script_parser() -> impl Parser> + C .repeated(), ) .foldl(|left, (op, right)| { - let span = left.span.start..right.span.end; + let span = (left.span.0, left.span.1.start..right.span.1.end); ast::Expr::BinOp { op, left: Box::new(left), @@ -615,7 +710,7 @@ fn script_parser() -> impl Parser> + C .repeated(), ) .foldl(|left, (op, right)| { - let span = left.span.start..right.span.end; + let span = (left.span.0, left.span.1.start..right.span.1.end); ast::Expr::BinOp { op, left: Box::new(left), @@ -643,7 +738,7 @@ fn script_parser() -> impl Parser> + C .repeated(), ) .foldl(|left, (op, right)| { - let span = left.span.start..right.span.end; + let span = (left.span.0, left.span.1.start..right.span.1.end); ast::Expr::BinOp { op, left: Box::new(left), @@ -664,7 +759,7 @@ fn script_parser() -> impl Parser> + C .repeated(), ) .foldl(|left, (op, right)| { - let span = left.span.start..right.span.end; + let span = (left.span.0, left.span.1.start..right.span.1.end); ast::Expr::BinOp { op, left: Box::new(left), @@ -682,7 +777,7 @@ fn script_parser() -> impl Parser> + C .repeated(), ) .foldl(|left, right| { - let span = left.span.start..right.span.end; + let span = (left.span.0, left.span.1.start..right.span.1.end); ast::Expr::First { value: Box::new(left), drop: Box::new(right), @@ -897,13 +992,13 @@ fn script_parser() -> impl Parser> + C }) } -fn type_parser() -> impl Parser> + Clone { +fn type_parser() -> impl Parser + Clone { filter_map(|span, tok| match tok { Token::Ident(id) if id == "i32" => Ok(ast::Type::I32), Token::Ident(id) if id == "i64" => Ok(ast::Type::I64), Token::Ident(id) if id == "f32" => Ok(ast::Type::F32), Token::Ident(id) if id == "f64" => Ok(ast::Type::F64), - _ => Err(Simple::expected_input_found( + _ => Err(ScriptError::expected_input_found( span, vec![ Some(Token::Ident("i32".into())), diff --git a/src/typecheck.rs b/src/typecheck.rs index e69dafc..6c8a37f 100644 --- a/src/typecheck.rs +++ b/src/typecheck.rs @@ -1,9 +1,9 @@ -use ariadne::{Color, Label, Report, ReportKind, Source}; +use ariadne::{Color, Label, Report, ReportKind}; use std::collections::HashMap; use crate::ast::{self, MemSize}; use crate::intrinsics::Intrinsics; -use crate::Span; +use crate::parser::{Sources, Span}; use ast::Type::*; type Result = std::result::Result; @@ -15,9 +15,9 @@ struct Var { } type Vars = HashMap; -pub fn tc_script(script: &mut ast::Script, source: &str) -> Result<()> { +pub fn tc_script(script: &mut ast::Script, sources: &Sources) -> Result<()> { let mut context = Context { - source, + sources, global_vars: HashMap::new(), functions: HashMap::new(), locals: ast::Locals::default(), @@ -41,7 +41,7 @@ pub fn tc_script(script: &mut ast::Script, source: &str) -> Result<()> { "Global already defined", &import.span, span, - source, + sources, ); } else { context.global_vars.insert( @@ -64,7 +64,7 @@ pub fn tc_script(script: &mut ast::Script, source: &str) -> Result<()> { "Function already defined", &import.span, &fnc.span, - source, + sources, ); } else { context.functions.insert( @@ -83,12 +83,12 @@ pub fn tc_script(script: &mut ast::Script, source: &str) -> Result<()> { for v in &mut script.global_vars { if let Some(Var { span, .. }) = context.global_vars.get(&v.name) { - result = report_duplicate_definition("Global already defined", &v.span, span, source); + result = report_duplicate_definition("Global already defined", &v.span, span, sources); } else { - tc_const(&mut v.value, source)?; + tc_const(&mut v.value, sources)?; if v.type_ != v.value.type_ { if v.type_.is_some() { - result = type_mismatch(v.type_, &v.span, v.value.type_, &v.value.span, source); + result = type_mismatch(v.type_, &v.span, v.value.type_, &v.value.span, sources); } else { v.type_ = v.value.type_; } @@ -107,8 +107,12 @@ pub fn tc_script(script: &mut ast::Script, source: &str) -> Result<()> { for f in &script.functions { let params = f.params.iter().map(|(_, t)| *t).collect(); if let Some(fnc) = context.functions.get(&f.name) { - result = - report_duplicate_definition("Function already defined", &f.span, &fnc.span, source); + result = report_duplicate_definition( + "Function already defined", + &f.span, + &fnc.span, + sources, + ); } else { context.functions.insert( f.name.clone(), @@ -132,7 +136,7 @@ pub fn tc_script(script: &mut ast::Script, source: &str) -> Result<()> { .or_else(|| context.global_vars.get(name).map(|v| &v.span)) { result = - report_duplicate_definition("Variable already defined", &f.span, span, source); + report_duplicate_definition("Variable already defined", &f.span, span, sources); } else { context.local_vars.insert( name.clone(), @@ -163,7 +167,7 @@ pub fn tc_script(script: &mut ast::Script, source: &str) -> Result<()> { f.locals = std::mem::take(&mut context.locals); if f.body.type_ != f.type_ { - result = type_mismatch(f.type_, &f.span, f.body.type_, &f.body.span, source); + result = type_mismatch(f.type_, &f.span, f.body.type_, &f.body.span, sources); } } @@ -171,7 +175,7 @@ pub fn tc_script(script: &mut ast::Script, source: &str) -> Result<()> { for f in &script.functions { if f.start { if !f.params.is_empty() || f.type_.is_some() { - Report::build(ReportKind::Error, (), f.span.start) + Report::build(ReportKind::Error, f.span.0, f.span.1.start) .with_message("Start function can't have params or a return value") .with_label( Label::new(f.span.clone()) @@ -179,7 +183,7 @@ pub fn tc_script(script: &mut ast::Script, source: &str) -> Result<()> { .with_color(Color::Red), ) .finish() - .eprint(Source::from(source)) + .eprint(sources) .unwrap(); result = Err(()); @@ -189,7 +193,7 @@ pub fn tc_script(script: &mut ast::Script, source: &str) -> Result<()> { "Start function already defined", &f.span, &prev.span, - source, + sources, ); } else { start_function = Some(f); @@ -198,14 +202,14 @@ pub fn tc_script(script: &mut ast::Script, source: &str) -> Result<()> { } for data in &mut script.data { - tc_const(&mut data.offset, source)?; + tc_const(&mut data.offset, sources)?; if data.offset.type_ != Some(I32) { result = type_mismatch( Some(I32), &data.offset.span, data.offset.type_, &data.offset.span, - source, + sources, ); } for values in &mut data.data { @@ -220,14 +224,14 @@ pub fn tc_script(script: &mut ast::Script, source: &str) -> Result<()> { ast::DataType::F64 => ast::Type::F64, }; for value in values { - tc_const(value, source)?; + tc_const(value, sources)?; if value.type_ != Some(needed_type) { result = type_mismatch( Some(needed_type), &value.span, value.type_, &value.span, - source, + sources, ); } } @@ -247,7 +251,7 @@ struct FunctionType { } struct Context<'a> { - source: &'a str, + sources: &'a Sources, global_vars: Vars, functions: HashMap, locals: ast::Locals, @@ -298,9 +302,9 @@ fn report_duplicate_definition( msg: &str, span: &Span, prev_span: &Span, - source: &str, + sources: &Sources, ) -> Result<()> { - Report::build(ReportKind::Error, (), span.start) + Report::build(ReportKind::Error, span.0, span.1.start) .with_message(msg) .with_label( Label::new(span.clone()) @@ -313,7 +317,7 @@ fn report_duplicate_definition( .with_color(Color::Yellow), ) .finish() - .eprint(Source::from(source)) + .eprint(sources) .unwrap(); Err(()) } @@ -323,9 +327,9 @@ fn type_mismatch( span1: &Span, type2: Option, span2: &Span, - source: &str, + sources: &Sources, ) -> Result<()> { - Report::build(ReportKind::Error, (), span2.start) + Report::build(ReportKind::Error, span2.0, span2.1.start) .with_message("Type mismatch") .with_label( Label::new(span1.clone()) @@ -348,13 +352,13 @@ fn type_mismatch( .with_color(Color::Red), ) .finish() - .eprint(Source::from(source)) + .eprint(sources) .unwrap(); Err(()) } -fn report_error(msg: &str, span: &Span, source: &str) -> Result<()> { - Report::build(ReportKind::Error, (), span.start) +fn report_error(msg: &str, span: &Span, sources: &Sources) -> Result<()> { + Report::build(ReportKind::Error, span.0, span.1.start) .with_message(msg) .with_label( Label::new(span.clone()) @@ -362,29 +366,29 @@ fn report_error(msg: &str, span: &Span, source: &str) -> Result<()> { .with_color(Color::Red), ) .finish() - .eprint(Source::from(source)) + .eprint(sources) .unwrap(); Err(()) } -fn expected_type(span: &Span, source: &str) -> Result<()> { +fn expected_type(span: &Span, sources: &Sources) -> Result<()> { report_error( "Expected value but found expression of type void", span, - source, + sources, ) } -fn unknown_variable(span: &Span, source: &str) -> Result<()> { - report_error("Unknown variable", span, source) +fn unknown_variable(span: &Span, sources: &Sources) -> Result<()> { + report_error("Unknown variable", span, sources) } -fn immutable_assign(span: &Span, source: &str) -> Result<()> { - report_error("Trying to assign to immutable variable", span, source) +fn immutable_assign(span: &Span, sources: &Sources) -> Result<()> { + report_error("Trying to assign to immutable variable", span, sources) } -fn missing_label(span: &Span, source: &str) -> Result<()> { - report_error("Label not found", span, source) +fn missing_label(span: &Span, sources: &Sources) -> Result<()> { + report_error("Label not found", span, sources) } fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<()> { @@ -423,11 +427,11 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() &expr.span, value.type_, &value.span, - context.source, + context.sources, ); } } else if value.type_.is_none() { - return expected_type(&value.span, context.source); + return expected_type(&value.span, context.sources); } else { *type_ = value.type_; } @@ -449,7 +453,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() *local_id = Some(id); context.local_vars.insert(name.clone(), id); } else { - return report_error("Type missing", &expr.span, context.source); + return report_error("Type missing", &expr.span, context.sources); } None } @@ -477,7 +481,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() &expr.span, value.type_, &value.span, - context.source, + context.sources, ); } None @@ -489,7 +493,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() ast::Expr::UnaryOp { op, ref mut value } => { tc_expression(context, value)?; if value.type_.is_none() { - return expected_type(&value.span, context.source); + return expected_type(&value.span, context.sources); } use ast::Type::*; use ast::UnaryOp::*; @@ -502,7 +506,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() &expr.span, value.type_, &value.span, - context.source, + context.sources, ) } }) @@ -521,11 +525,11 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() &left.span, right.type_, &right.span, - context.source, + context.sources, ); } } else { - return expected_type(&left.span, context.source); + return expected_type(&left.span, context.sources); } use ast::BinOp::*; match op { @@ -537,7 +541,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() &left.span, left.type_, &left.span, - context.source, + context.sources, ); } else { left.type_ @@ -551,7 +555,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() &left.span, left.type_, &left.span, - context.source, + context.sources, ); } else { Some(I32) @@ -569,7 +573,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() } else if let Some(&Var { type_, .. }) = context.global_vars.get(name) { Some(type_) } else { - return unknown_variable(&expr.span, context.source); + return unknown_variable(&expr.span, context.sources); } } ast::Expr::Assign { @@ -583,7 +587,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() *local_id = Some(id); let local = &context.locals[id]; if local.index.is_none() { - return immutable_assign(&expr.span, context.source); + return immutable_assign(&expr.span, context.sources); } (local.type_, &local.span) } else if let Some(&Var { @@ -593,15 +597,15 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() }) = context.global_vars.get(name) { if !mutable { - return immutable_assign(&expr.span, context.source); + return immutable_assign(&expr.span, context.sources); } (type_, span) } else { - return unknown_variable(&expr.span, context.source); + return unknown_variable(&expr.span, context.sources); }; if value.type_ != Some(type_) { - return type_mismatch(Some(type_), span, value.type_, &value.span, context.source); + return type_mismatch(Some(type_), span, value.type_, &value.span, context.sources); } None } @@ -616,7 +620,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() let local = &context.locals[id]; if local.index.is_none() { - return immutable_assign(&expr.span, context.source); + return immutable_assign(&expr.span, context.sources); } if value.type_ != Some(local.type_) { @@ -625,13 +629,13 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() &local.span, value.type_, &value.span, - context.source, + context.sources, ); } Some(local.type_) } else { - return unknown_variable(&expr.span, context.source); + return unknown_variable(&expr.span, context.sources); } } ast::Expr::Loop { @@ -652,13 +656,13 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() context.block_stack.pop(); if block.type_ != None { // TODO: implement, requires branches to optionally provide values - return type_mismatch(None, &expr.span, block.type_, &block.span, context.source); + return type_mismatch(None, &expr.span, block.type_, &block.span, context.sources); } None } ast::Expr::Branch(ref label) => { if !context.block_stack.contains(label) { - return missing_label(&expr.span, context.source); + return missing_label(&expr.span, context.sources); } None } @@ -673,11 +677,11 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() &expr.span, condition.type_, &condition.span, - context.source, + context.sources, ); } if !context.block_stack.contains(label) { - return missing_label(&expr.span, context.source); + return missing_label(&expr.span, context.sources); } None } @@ -687,7 +691,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() } => { tc_expression(context, value)?; if value.type_.is_none() { - return expected_type(&expr.span, context.source); + return expected_type(&expr.span, context.sources); } Some(type_) } @@ -698,7 +702,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() for param in params.iter_mut() { tc_expression(context, param)?; if param.type_.is_none() { - return expected_type(¶m.span, context.source); + return expected_type(¶m.span, context.sources); } } if let Some(load) = context.intrinsics.find_load(name) { @@ -713,11 +717,11 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() &expr.span, value.type_, &value.span, - context.source, + context.sources, )?; } } else { - return report_error("Missing parameters", &expr.span, context.source); + return report_error("Missing parameters", &expr.span, context.sources); } tc_memarg(context, &mut params[1..], &expr.span)?; None @@ -732,8 +736,9 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() { *rtype } else { - let mut report = Report::build(ReportKind::Error, (), expr.span.start) - .with_message("No matching function found"); + let mut report = + Report::build(ReportKind::Error, expr.span.0, expr.span.1.start) + .with_message("No matching function found"); for (params, rtype) in type_map { let param_str: Vec<_> = params.into_iter().map(|t| t.to_string()).collect(); let msg = format!( @@ -748,17 +753,14 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() ); report = report.with_label(Label::new(expr.span.clone()).with_message(msg)); } - report - .finish() - .eprint(Source::from(context.source)) - .unwrap(); + report.finish().eprint(context.sources).unwrap(); return Err(()); } } else { return report_error( &format!("Unknown function {}", name), &expr.span, - context.source, + context.sources, ); } } @@ -776,7 +778,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() &condition.span, condition.type_, &condition.span, - context.source, + context.sources, ); } if if_true.type_.is_some() { @@ -786,11 +788,11 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() &if_true.span, if_false.type_, &if_false.span, - context.source, + context.sources, ); } } else { - return expected_type(&if_true.span, context.source); + return expected_type(&if_true.span, context.sources); } if_true.type_ } @@ -809,7 +811,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() &if_true.span, if_false.type_, &if_false.span, - context.source, + context.sources, ); } else { if_true.type_ @@ -827,7 +829,7 @@ fn tc_expression(context: &mut Context, expr: &mut ast::Expression) -> Result<() &expr.span, value.type_, &value.span, - context.source, + context.sources, ); } } @@ -851,14 +853,14 @@ fn tc_mem_location<'a>( mem_location: &mut ast::MemoryLocation, ) -> Result<()> { tc_expression(context, &mut mem_location.left)?; - tc_const(&mut mem_location.right, context.source)?; + tc_const(&mut mem_location.right, context.sources)?; if mem_location.left.type_ != Some(I32) { return type_mismatch( Some(I32), &mem_location.left.span, mem_location.left.type_, &mem_location.left.span, - context.source, + context.sources, ); } if mem_location.right.type_ != Some(I32) { @@ -867,20 +869,20 @@ fn tc_mem_location<'a>( &mem_location.right.span, mem_location.right.type_, &mem_location.right.span, - context.source, + context.sources, ); } Ok(()) } -fn tc_const(expr: &mut ast::Expression, source: &str) -> Result<()> { +fn tc_const(expr: &mut ast::Expression, sources: &Sources) -> Result<()> { use ast::Expr::*; expr.type_ = Some(match expr.expr { I32Const(_) => I32, I64Const(_) => I64, F32Const(_) => F32, F64Const(_) => F64, - _ => return report_error("Expected constant value", &expr.span, source), + _ => return report_error("Expected constant value", &expr.span, sources), }); Ok(()) } @@ -892,16 +894,16 @@ fn tc_memarg(context: &mut Context, params: &mut [ast::Expression], span: &Span) } else { "Too many MemArg parameters" }; - return report_error(msg, span, context.source); + return report_error(msg, span, context.sources); } for (index, param) in params.iter_mut().enumerate() { tc_expression(context, param)?; if param.type_ != Some(I32) { - return type_mismatch(Some(I32), &span, param.type_, ¶m.span, context.source); + return type_mismatch(Some(I32), &span, param.type_, ¶m.span, context.sources); } if index > 0 { - tc_const(param, context.source)?; + tc_const(param, context.sources)?; } if index == 2 { let align = param.const_i32(); @@ -909,7 +911,7 @@ fn tc_memarg(context: &mut Context, params: &mut [ast::Expression], span: &Span) return report_error( &format!("Alignment {} out of range (0-4)", align), ¶m.span, - context.source, + context.sources, ); } }