Compare commits
2 Commits
63360e5617
...
ec55e2e8f0
Author | SHA1 | Date | |
---|---|---|---|
|
ec55e2e8f0 | ||
|
3ed5f1d16c |
@ -9,9 +9,10 @@ mod operators;
|
|||||||
pub use operators::*;
|
pub use operators::*;
|
||||||
pub use visitor::ASTVisitor;
|
pub use visitor::ASTVisitor;
|
||||||
pub use walker::walk_ast;
|
pub use walker::walk_ast;
|
||||||
|
use crate::tokenizing::Location;
|
||||||
|
|
||||||
/// An abstract identifier for an AST node
|
/// An abstract identifier for an AST node
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Default)]
|
||||||
pub struct ItemId {
|
pub struct ItemId {
|
||||||
idx: u32,
|
idx: u32,
|
||||||
}
|
}
|
||||||
@ -57,6 +58,8 @@ pub struct AST {
|
|||||||
pub struct Statement {
|
pub struct Statement {
|
||||||
#[derivative(PartialEq="ignore")]
|
#[derivative(PartialEq="ignore")]
|
||||||
pub id: ItemId,
|
pub id: ItemId,
|
||||||
|
#[derivative(PartialEq="ignore")]
|
||||||
|
pub location: Location,
|
||||||
pub kind: StatementKind,
|
pub kind: StatementKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ impl ASTVisitor for Tester {
|
|||||||
#[test]
|
#[test]
|
||||||
fn foo() {
|
fn foo() {
|
||||||
let mut tester = Tester { count: 0, float_count: 0 };
|
let mut tester = Tester { count: 0, float_count: 0 };
|
||||||
let (ast, _) = quick_ast(r#"
|
let ast = quick_ast(r#"
|
||||||
import gragh
|
import gragh
|
||||||
|
|
||||||
let a = 20 + 84
|
let a = 20 + 84
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use crate::parsing::ParseError;
|
use crate::parsing::ParseError;
|
||||||
use crate::schala::{SourceReference, Stage};
|
use crate::schala::{SourceReference, Stage};
|
||||||
use crate::source_map::Location;
|
use crate::tokenizing::{Token, TokenKind, Location};
|
||||||
use crate::tokenizing::{Token, TokenKind};
|
|
||||||
use crate::typechecking::TypeError;
|
use crate::typechecking::TypeError;
|
||||||
|
|
||||||
pub struct SchalaError {
|
pub struct SchalaError {
|
||||||
@ -85,7 +84,7 @@ struct Error {
|
|||||||
fn format_parse_error(error: ParseError, source_reference: &SourceReference) -> String {
|
fn format_parse_error(error: ParseError, source_reference: &SourceReference) -> String {
|
||||||
let line_num = error.token.location.line_num;
|
let line_num = error.token.location.line_num;
|
||||||
let ch = error.token.location.char_num;
|
let ch = error.token.location.char_num;
|
||||||
let line_from_program = source_reference.get_line(line_num);
|
let line_from_program = source_reference.get_line(line_num as usize);
|
||||||
let location_pointer = format!("{}^", " ".repeat(ch));
|
let location_pointer = format!("{}^", " ".repeat(ch));
|
||||||
|
|
||||||
let line_num_digits = format!("{}", line_num).chars().count();
|
let line_num_digits = format!("{}", line_num).chars().count();
|
||||||
|
@ -9,9 +9,8 @@ use crate::reduced_ast::reduce;
|
|||||||
use crate::eval::State;
|
use crate::eval::State;
|
||||||
|
|
||||||
fn evaluate_all_outputs(input: &str) -> Vec<Result<String, String>> {
|
fn evaluate_all_outputs(input: &str) -> Vec<Result<String, String>> {
|
||||||
let (mut ast, source_map) = crate::util::quick_ast(input);
|
let mut ast = crate::util::quick_ast(input);
|
||||||
let source_map = Rc::new(RefCell::new(source_map));
|
let symbol_table = Rc::new(RefCell::new(SymbolTable::new()));
|
||||||
let symbol_table = Rc::new(RefCell::new(SymbolTable::new(source_map)));
|
|
||||||
symbol_table.borrow_mut().add_top_level_symbols(&ast).unwrap();
|
symbol_table.borrow_mut().add_top_level_symbols(&ast).unwrap();
|
||||||
{
|
{
|
||||||
let mut scope_resolver = ScopeResolver::new(symbol_table.clone());
|
let mut scope_resolver = ScopeResolver::new(symbol_table.clone());
|
||||||
|
@ -30,7 +30,6 @@ mod scope_resolution;
|
|||||||
mod builtin;
|
mod builtin;
|
||||||
mod reduced_ast;
|
mod reduced_ast;
|
||||||
mod eval;
|
mod eval;
|
||||||
mod source_map;
|
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
mod schala;
|
mod schala;
|
||||||
|
@ -166,10 +166,9 @@ use std::str::FromStr;
|
|||||||
use crate::tokenizing::*;
|
use crate::tokenizing::*;
|
||||||
use crate::tokenizing::Kw::*;
|
use crate::tokenizing::Kw::*;
|
||||||
use crate::tokenizing::TokenKind::*;
|
use crate::tokenizing::TokenKind::*;
|
||||||
|
use crate::tokenizing::Location;
|
||||||
|
|
||||||
use crate::source_map::Location;
|
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
use crate::schala::SourceMapHandle;
|
|
||||||
|
|
||||||
/// Represents a parsing error
|
/// Represents a parsing error
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -202,7 +201,6 @@ pub struct Parser {
|
|||||||
parse_level: u32,
|
parse_level: u32,
|
||||||
restrictions: ParserRestrictions,
|
restrictions: ParserRestrictions,
|
||||||
id_store: ItemIdStore,
|
id_store: ItemIdStore,
|
||||||
source_map: SourceMapHandle
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -247,14 +245,13 @@ impl TokenHandler {
|
|||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
/// Create a new parser initialized with some tokens.
|
/// Create a new parser initialized with some tokens.
|
||||||
pub fn new(source_map: SourceMapHandle) -> Parser {
|
pub fn new() -> Parser {
|
||||||
Parser {
|
Parser {
|
||||||
token_handler: TokenHandler::new(vec![]),
|
token_handler: TokenHandler::new(vec![]),
|
||||||
parse_record: vec![],
|
parse_record: vec![],
|
||||||
parse_level: 0,
|
parse_level: 0,
|
||||||
restrictions: ParserRestrictions { no_struct_literal: false },
|
restrictions: ParserRestrictions { no_struct_literal: false },
|
||||||
id_store: ItemIdStore::new(),
|
id_store: ItemIdStore::new(),
|
||||||
source_map,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,8 +380,7 @@ impl Parser {
|
|||||||
_ => self.expression().map(|expr| { StatementKind::Expression(expr) } ),
|
_ => self.expression().map(|expr| { StatementKind::Expression(expr) } ),
|
||||||
}?;
|
}?;
|
||||||
let id = self.id_store.fresh();
|
let id = self.id_store.fresh();
|
||||||
self.source_map.borrow_mut().add_location(&id, tok.location);
|
Ok(Statement { kind, id, location: tok.location })
|
||||||
Ok(Statement { kind, id })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[recursive_descent_method]
|
#[recursive_descent_method]
|
||||||
@ -1040,11 +1036,12 @@ impl Parser {
|
|||||||
|
|
||||||
#[recursive_descent_method]
|
#[recursive_descent_method]
|
||||||
fn expr_or_block(&mut self) -> ParseResult<Block> {
|
fn expr_or_block(&mut self) -> ParseResult<Block> {
|
||||||
match self.token_handler.peek_kind() {
|
let tok = self.token_handler.peek();
|
||||||
|
match tok.get_kind() {
|
||||||
LCurlyBrace => self.block(),
|
LCurlyBrace => self.block(),
|
||||||
_ => {
|
_ => {
|
||||||
let expr = self.expression()?;
|
let expr = self.expression()?;
|
||||||
let s = Statement { id: self.id_store.fresh(), kind: StatementKind::Expression(expr) };
|
let s = Statement { id: self.id_store.fresh(), location: tok.location, kind: StatementKind::Expression(expr) };
|
||||||
Ok(vec![s])
|
Ok(vec![s])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#![cfg(test)]
|
#![cfg(test)]
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use crate::tokenizing::Location;
|
||||||
use super::{Parser, ParseResult, tokenize};
|
use super::{Parser, ParseResult, tokenize};
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
use super::Declaration::*;
|
use super::Declaration::*;
|
||||||
@ -14,10 +14,8 @@ use super::Variant::*;
|
|||||||
use super::ForBody::*;
|
use super::ForBody::*;
|
||||||
|
|
||||||
fn make_parser(input: &str) -> Parser {
|
fn make_parser(input: &str) -> Parser {
|
||||||
let source_map = crate::source_map::SourceMap::new();
|
|
||||||
let source_map_handle = Rc::new(RefCell::new(source_map));
|
|
||||||
let tokens: Vec<crate::tokenizing::Token> = tokenize(input);
|
let tokens: Vec<crate::tokenizing::Token> = tokenize(input);
|
||||||
let mut parser = super::Parser::new(source_map_handle);
|
let mut parser = super::Parser::new();
|
||||||
parser.add_new_tokens(tokens);
|
parser.add_new_tokens(tokens);
|
||||||
parser
|
parser
|
||||||
}
|
}
|
||||||
@ -27,6 +25,15 @@ fn parse(input: &str) -> ParseResult<AST> {
|
|||||||
parser.parse()
|
parser.parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO maybe can be const?
|
||||||
|
fn make_statement(kind: StatementKind) -> Statement {
|
||||||
|
Statement {
|
||||||
|
location: Location::default(),
|
||||||
|
id: ItemId::default(),
|
||||||
|
kind,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! parse_test {
|
macro_rules! parse_test {
|
||||||
($string:expr, $correct:expr) => {
|
($string:expr, $correct:expr) => {
|
||||||
assert_eq!(parse($string).unwrap(), $correct)
|
assert_eq!(parse($string).unwrap(), $correct)
|
||||||
@ -61,19 +68,19 @@ macro_rules! tys {
|
|||||||
|
|
||||||
macro_rules! decl {
|
macro_rules! decl {
|
||||||
($expr_type:expr) => {
|
($expr_type:expr) => {
|
||||||
Statement { id: ItemIdStore::new_id(), kind: StatementKind::Declaration($expr_type) }
|
make_statement(StatementKind::Declaration($expr_type))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! import {
|
macro_rules! import {
|
||||||
($import_spec:expr) => {
|
($import_spec:expr) => {
|
||||||
Statement { id: ItemIdStore::new_id(), kind: StatementKind::Import($import_spec) }
|
make_statement(StatementKind::Import($import_spec))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! module {
|
macro_rules! module {
|
||||||
($module_spec:expr) => {
|
($module_spec:expr) => {
|
||||||
Statement { id: ItemIdStore::new_id(), kind: StatementKind::Module($module_spec) }
|
make_statement(StatementKind::Module($module_spec))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,10 +106,9 @@ macro_rules! prefexp {
|
|||||||
($op:expr, $lhs:expr) => { PrefixExp(PrefixOp::from_str($op).unwrap(), bx!(Expression::new(ItemIdStore::new_id(), $lhs).into())) }
|
($op:expr, $lhs:expr) => { PrefixExp(PrefixOp::from_str($op).unwrap(), bx!(Expression::new(ItemIdStore::new_id(), $lhs).into())) }
|
||||||
}
|
}
|
||||||
macro_rules! exst {
|
macro_rules! exst {
|
||||||
($expr_type:expr) => { Statement { id: ItemIdStore::new_id(), kind: StatementKind::Expression(Expression::new(ItemIdStore::new_id(), $expr_type).into())} };
|
($expr_type:expr) => { make_statement(StatementKind::Expression(Expression::new(ItemIdStore::new_id(), $expr_type).into())) };
|
||||||
($expr_type:expr, $type_anno:expr) => { Statement { id: ItemIdStore::new_id(), kind: StatementKind::Expression(Expression::with_anno(ItemIdStore::new_id(), $expr_type, $type_anno).into())} };
|
($expr_type:expr, $type_anno:expr) => { make_statement(StatementKind::Expression(Expression::with_anno(ItemIdStore::new_id(), $expr_type, $type_anno).into())) };
|
||||||
($op:expr, $lhs:expr, $rhs:expr) => { Statement { id: ItemIdStore::new_id(), ,kind: StatementKind::Expression(ex!(binexp!($op, $lhs, $rhs)))}
|
($op:expr, $lhs:expr, $rhs:expr) => { make_statement(StatementKind::Expression(ex!(binexp!($op, $lhs, $rhs)))) };
|
||||||
};
|
|
||||||
(s $statement_text:expr) => {
|
(s $statement_text:expr) => {
|
||||||
{
|
{
|
||||||
let mut parser = make_parser($statement_text);
|
let mut parser = make_parser($statement_text);
|
||||||
|
@ -6,11 +6,10 @@ use std::rc::Rc;
|
|||||||
use schala_repl::{ProgrammingLanguageInterface,
|
use schala_repl::{ProgrammingLanguageInterface,
|
||||||
ComputationRequest, ComputationResponse,
|
ComputationRequest, ComputationResponse,
|
||||||
LangMetaRequest, LangMetaResponse, GlobalOutputStats};
|
LangMetaRequest, LangMetaResponse, GlobalOutputStats};
|
||||||
use crate::{reduced_ast, tokenizing, parsing, eval, typechecking, symbol_table, source_map};
|
use crate::{reduced_ast, tokenizing, parsing, eval, typechecking, symbol_table};
|
||||||
use crate::error::SchalaError;
|
use crate::error::SchalaError;
|
||||||
|
|
||||||
pub type SymbolTableHandle = Rc<RefCell<symbol_table::SymbolTable>>;
|
pub type SymbolTableHandle = Rc<RefCell<symbol_table::SymbolTable>>;
|
||||||
pub type SourceMapHandle = Rc<RefCell<source_map::SourceMap>>;
|
|
||||||
|
|
||||||
/// All the state necessary to parse and execute a Schala program are stored in this struct.
|
/// All the state necessary to parse and execute a Schala program are stored in this struct.
|
||||||
/// `state` represents the execution state for the AST-walking interpreter, the other fields
|
/// `state` represents the execution state for the AST-walking interpreter, the other fields
|
||||||
@ -18,7 +17,6 @@ pub type SourceMapHandle = Rc<RefCell<source_map::SourceMap>>;
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct Schala {
|
pub struct Schala {
|
||||||
source_reference: SourceReference,
|
source_reference: SourceReference,
|
||||||
source_map: SourceMapHandle,
|
|
||||||
state: eval::State<'static>,
|
state: eval::State<'static>,
|
||||||
symbol_table: SymbolTableHandle,
|
symbol_table: SymbolTableHandle,
|
||||||
resolver: crate::scope_resolution::ScopeResolver<'static>,
|
resolver: crate::scope_resolution::ScopeResolver<'static>,
|
||||||
@ -40,17 +38,15 @@ impl Schala {
|
|||||||
impl Schala {
|
impl Schala {
|
||||||
/// Creates a new Schala environment *without* any prelude.
|
/// Creates a new Schala environment *without* any prelude.
|
||||||
fn new_blank_env() -> Schala {
|
fn new_blank_env() -> Schala {
|
||||||
let source_map = Rc::new(RefCell::new(source_map::SourceMap::new()));
|
let symbols = Rc::new(RefCell::new(symbol_table::SymbolTable::new()));
|
||||||
let symbols = Rc::new(RefCell::new(symbol_table::SymbolTable::new(source_map.clone())));
|
|
||||||
Schala {
|
Schala {
|
||||||
//TODO maybe these can be the same structure
|
//TODO maybe these can be the same structure
|
||||||
source_reference: SourceReference::new(),
|
source_reference: SourceReference::new(),
|
||||||
symbol_table: symbols.clone(),
|
symbol_table: symbols.clone(),
|
||||||
source_map: source_map.clone(),
|
|
||||||
resolver: crate::scope_resolution::ScopeResolver::new(symbols.clone()),
|
resolver: crate::scope_resolution::ScopeResolver::new(symbols.clone()),
|
||||||
state: eval::State::new(),
|
state: eval::State::new(),
|
||||||
type_context: typechecking::TypeContext::new(),
|
type_context: typechecking::TypeContext::new(),
|
||||||
active_parser: parsing::Parser::new(source_map)
|
active_parser: parsing::Parser::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
use crate::ast::ItemId;
|
|
||||||
|
|
||||||
pub type LineNumber = usize;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
||||||
pub struct Location {
|
|
||||||
pub line_num: LineNumber,
|
|
||||||
pub char_num: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Location {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}:{}", self.line_num, self.char_num)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SourceMap {
|
|
||||||
map: HashMap<ItemId, Location>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SourceMap {
|
|
||||||
pub fn new() -> SourceMap {
|
|
||||||
SourceMap { map: HashMap::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_location(&mut self, id: &ItemId, loc: Location) {
|
|
||||||
self.map.insert(id.clone(), loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lookup(&self, id: &ItemId) -> Option<Location> {
|
|
||||||
match self.map.get(id) {
|
|
||||||
Some(loc) => Some(loc.clone()),
|
|
||||||
None => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,8 +4,7 @@ use std::rc::Rc;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use crate::schala::SourceMapHandle;
|
use crate::tokenizing::LineNumber;
|
||||||
use crate::source_map::{SourceMap, LineNumber};
|
|
||||||
use crate::ast;
|
use crate::ast;
|
||||||
use crate::ast::{ItemId, TypeBody, TypeSingletonName, Signature, Statement, StatementKind, ModuleSpecifier};
|
use crate::ast::{ItemId, TypeBody, TypeSingletonName, Signature, Statement, StatementKind, ModuleSpecifier};
|
||||||
use crate::typechecking::TypeName;
|
use crate::typechecking::TypeName;
|
||||||
@ -24,6 +23,8 @@ macro_rules! fqsn {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod source_map;
|
||||||
|
use source_map::SourceMap;
|
||||||
mod symbol_trie;
|
mod symbol_trie;
|
||||||
use symbol_trie::SymbolTrie;
|
use symbol_trie::SymbolTrie;
|
||||||
mod test;
|
mod test;
|
||||||
@ -93,16 +94,16 @@ impl ScopeSegment {
|
|||||||
|
|
||||||
//cf. p. 150 or so of Language Implementation Patterns
|
//cf. p. 150 or so of Language Implementation Patterns
|
||||||
pub struct SymbolTable {
|
pub struct SymbolTable {
|
||||||
source_map_handle: SourceMapHandle,
|
source_map: SourceMap,
|
||||||
symbol_path_to_symbol: HashMap<FullyQualifiedSymbolName, Symbol>,
|
symbol_path_to_symbol: HashMap<FullyQualifiedSymbolName, Symbol>,
|
||||||
id_to_fqsn: HashMap<ItemId, FullyQualifiedSymbolName>,
|
id_to_fqsn: HashMap<ItemId, FullyQualifiedSymbolName>,
|
||||||
symbol_trie: SymbolTrie,
|
symbol_trie: SymbolTrie,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SymbolTable {
|
impl SymbolTable {
|
||||||
pub fn new(source_map_handle: SourceMapHandle) -> SymbolTable {
|
pub fn new() -> SymbolTable {
|
||||||
SymbolTable {
|
SymbolTable {
|
||||||
source_map_handle,
|
source_map: SourceMap::new(),
|
||||||
symbol_path_to_symbol: HashMap::new(),
|
symbol_path_to_symbol: HashMap::new(),
|
||||||
id_to_fqsn: HashMap::new(),
|
id_to_fqsn: HashMap::new(),
|
||||||
symbol_trie: SymbolTrie::new()
|
symbol_trie: SymbolTrie::new()
|
||||||
@ -198,15 +199,17 @@ impl SymbolTable {
|
|||||||
|
|
||||||
for statement in statements.iter() {
|
for statement in statements.iter() {
|
||||||
match statement {
|
match statement {
|
||||||
Statement { kind: StatementKind::Declaration(decl), id } => {
|
Statement { kind: StatementKind::Declaration(decl), id, location, } => {
|
||||||
|
self.source_map.add_location(id, *location);
|
||||||
|
|
||||||
match decl {
|
match decl {
|
||||||
FuncSig(ref signature) => {
|
FuncSig(ref signature) => {
|
||||||
seen_identifiers.try_register(&signature.name, &id, &self.source_map_handle.borrow())
|
seen_identifiers.try_register(&signature.name, &id, &self.source_map)
|
||||||
.map_err(|line| format!("Duplicate function definition: {}. It's already defined at {}", signature.name, line))?;
|
.map_err(|line| format!("Duplicate function definition: {}. It's already defined at {}", signature.name, line))?;
|
||||||
self.add_function_signature(signature, scope_name_stack)?
|
self.add_function_signature(signature, scope_name_stack)?
|
||||||
}
|
}
|
||||||
FuncDecl(ref signature, ref body) => {
|
FuncDecl(ref signature, ref body) => {
|
||||||
seen_identifiers.try_register(&signature.name, &id, &self.source_map_handle.borrow())
|
seen_identifiers.try_register(&signature.name, &id, &self.source_map)
|
||||||
.map_err(|line| format!("Duplicate function definition: {}. It's already defined at {}", signature.name, line))?;
|
.map_err(|line| format!("Duplicate function definition: {}. It's already defined at {}", signature.name, line))?;
|
||||||
self.add_function_signature(signature, scope_name_stack)?;
|
self.add_function_signature(signature, scope_name_stack)?;
|
||||||
scope_name_stack.push(ScopeSegment{
|
scope_name_stack.push(ScopeSegment{
|
||||||
@ -217,20 +220,21 @@ impl SymbolTable {
|
|||||||
output?
|
output?
|
||||||
},
|
},
|
||||||
TypeDecl { name, body, mutable } => {
|
TypeDecl { name, body, mutable } => {
|
||||||
seen_identifiers.try_register(&name.name, &id, &self.source_map_handle.borrow())
|
seen_identifiers.try_register(&name.name, &id, &self.source_map)
|
||||||
.map_err(|line| format!("Duplicate type definition: {}. It's already defined at {}", name.name, line))?;
|
.map_err(|line| format!("Duplicate type definition: {}. It's already defined at {}", name.name, line))?;
|
||||||
self.add_type_decl(name, body, mutable, scope_name_stack)?
|
self.add_type_decl(name, body, mutable, scope_name_stack)?
|
||||||
},
|
},
|
||||||
Binding { name, .. } => {
|
Binding { name, .. } => {
|
||||||
seen_identifiers.try_register(&name, &id, &self.source_map_handle.borrow())
|
seen_identifiers.try_register(&name, &id, &self.source_map)
|
||||||
.map_err(|line| format!("Duplicate variable definition: {}. It's already defined at {}", name, line))?;
|
.map_err(|line| format!("Duplicate variable definition: {}. It's already defined at {}", name, line))?;
|
||||||
self.add_new_symbol(name, scope_name_stack, SymbolSpec::Binding);
|
self.add_new_symbol(name, scope_name_stack, SymbolSpec::Binding);
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Statement { kind: StatementKind::Module(ModuleSpecifier { name, contents}), id } => {
|
Statement { kind: StatementKind::Module(ModuleSpecifier { name, contents}), id, location } => {
|
||||||
seen_modules.try_register(&name, &id, &self.source_map_handle.borrow())
|
self.source_map.add_location(id, *location);
|
||||||
|
seen_modules.try_register(&name, &id, &self.source_map)
|
||||||
.map_err(|line| format!("Duplicate module definition: {}. It's already defined at {}", name, line))?;
|
.map_err(|line| format!("Duplicate module definition: {}. It's already defined at {}", name, line))?;
|
||||||
scope_name_stack.push(ScopeSegment { name: name.clone() });
|
scope_name_stack.push(ScopeSegment { name: name.clone() });
|
||||||
let output = self.add_symbols_from_scope(contents, scope_name_stack);
|
let output = self.add_symbols_from_scope(contents, scope_name_stack);
|
||||||
|
27
schala-lang/language/src/symbol_table/source_map.rs
Normal file
27
schala-lang/language/src/symbol_table/source_map.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::ast::ItemId;
|
||||||
|
use crate::tokenizing::Location;
|
||||||
|
|
||||||
|
|
||||||
|
//TODO rename this type to make its purpose clearer
|
||||||
|
pub struct SourceMap {
|
||||||
|
map: HashMap<ItemId, Location>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SourceMap {
|
||||||
|
pub fn new() -> SourceMap {
|
||||||
|
SourceMap { map: HashMap::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_location(&mut self, id: &ItemId, loc: Location) {
|
||||||
|
self.map.insert(id.clone(), loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn lookup(&self, id: &ItemId) -> Option<Location> {
|
||||||
|
match self.map.get(id) {
|
||||||
|
Some(loc) => Some(loc.clone()),
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,10 @@
|
|||||||
#![cfg(test)]
|
#![cfg(test)]
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::util::quick_ast;
|
use crate::util::quick_ast;
|
||||||
|
|
||||||
fn add_symbols_from_source(src: &str) -> (SymbolTable, Result<(), String>) {
|
fn add_symbols_from_source(src: &str) -> (SymbolTable, Result<(), String>) {
|
||||||
let (ast, source_map) = quick_ast(src);
|
let ast = quick_ast(src);
|
||||||
let source_map = Rc::new(RefCell::new(source_map));
|
let mut symbol_table = SymbolTable::new();
|
||||||
let mut symbol_table = SymbolTable::new(source_map);
|
|
||||||
let result = symbol_table.add_top_level_symbols(&ast);
|
let result = symbol_table.add_top_level_symbols(&ast);
|
||||||
(symbol_table, result)
|
(symbol_table, result)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,20 @@
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::{iter::{Iterator, Peekable}, convert::TryFrom, rc::Rc, fmt};
|
use std::{iter::{Iterator, Peekable}, convert::TryFrom, rc::Rc, fmt};
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
use crate::source_map::Location;
|
pub type LineNumber = u32;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
||||||
|
pub struct Location {
|
||||||
|
pub(crate) line_num: LineNumber,
|
||||||
|
pub(crate) char_num: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Location {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}:{}", self.line_num, self.char_num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum TokenKind {
|
pub enum TokenKind {
|
||||||
@ -95,7 +108,7 @@ impl TryFrom<&str> for Kw {
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
pub kind: TokenKind,
|
pub kind: TokenKind,
|
||||||
pub location: Location,
|
pub(crate) location: Location,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Token {
|
impl Token {
|
||||||
@ -171,7 +184,7 @@ pub fn tokenize(input: &str) -> Vec<Token> {
|
|||||||
c if is_operator(&c) => handle_operator(c, &mut input),
|
c if is_operator(&c) => handle_operator(c, &mut input),
|
||||||
unknown => Error(format!("Unexpected character: {}", unknown)),
|
unknown => Error(format!("Unexpected character: {}", unknown)),
|
||||||
};
|
};
|
||||||
let location = Location { line_num, char_num };
|
let location = Location { line_num: line_num.try_into().unwrap(), char_num };
|
||||||
tokens.push(Token { kind: cur_tok_kind, location });
|
tokens.push(Token { kind: cur_tok_kind, location });
|
||||||
}
|
}
|
||||||
tokens
|
tokens
|
||||||
|
@ -464,7 +464,7 @@ mod typechecking_tests {
|
|||||||
macro_rules! assert_type_in_fresh_context {
|
macro_rules! assert_type_in_fresh_context {
|
||||||
($string:expr, $type:expr) => {
|
($string:expr, $type:expr) => {
|
||||||
let mut tc = TypeContext::new();
|
let mut tc = TypeContext::new();
|
||||||
let (ref ast, _) = crate::util::quick_ast($string);
|
let ref ast = crate::util::quick_ast($string);
|
||||||
let ty = tc.typecheck(ast).unwrap();
|
let ty = tc.typecheck(ast).unwrap();
|
||||||
assert_eq!(ty, $type)
|
assert_eq!(ty, $type)
|
||||||
}
|
}
|
||||||
|
@ -48,18 +48,13 @@ impl<'a, T, V> ScopeStack<'a, T, V> where T: Hash + Eq {
|
|||||||
|
|
||||||
/// this is intended for use in tests, and does no error-handling whatsoever
|
/// this is intended for use in tests, and does no error-handling whatsoever
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn quick_ast(input: &str) -> (crate::ast::AST, crate::source_map::SourceMap) {
|
pub fn quick_ast(input: &str) -> crate::ast::AST {
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
let source_map = crate::source_map::SourceMap::new();
|
|
||||||
let source_map_handle = Rc::new(RefCell::new(source_map));
|
|
||||||
let tokens = crate::tokenizing::tokenize(input);
|
let tokens = crate::tokenizing::tokenize(input);
|
||||||
let mut parser = crate::parsing::Parser::new(source_map_handle.clone());
|
let mut parser = crate::parsing::Parser::new();
|
||||||
parser.add_new_tokens(tokens);
|
parser.add_new_tokens(tokens);
|
||||||
let output = parser.parse();
|
let output = parser.parse();
|
||||||
std::mem::drop(parser);
|
std::mem::drop(parser);
|
||||||
(output.unwrap(), Rc::try_unwrap(source_map_handle).map_err(|_| ()).unwrap().into_inner())
|
output.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_macros)]
|
#[allow(unused_macros)]
|
||||||
|
Loading…
Reference in New Issue
Block a user