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