Use BTree{Map,Set} instead of Hash{Map,Set} to ensure deterministic output
Fixes #8
This commit is contained in:
committed by
Chris Fallin
parent
efe7df7f45
commit
0e02ec4cba
@@ -4,11 +4,11 @@ use crate::ir::{ExprInst, InstId, PatternInst, Value};
|
|||||||
use crate::sema::ExternalSig;
|
use crate::sema::ExternalSig;
|
||||||
use crate::sema::{TermEnv, TermId, Type, TypeEnv, TypeId, Variant};
|
use crate::sema::{TermEnv, TermId, Type, TypeEnv, TypeId, Variant};
|
||||||
use crate::trie::{TrieEdge, TrieNode, TrieSymbol};
|
use crate::trie::{TrieEdge, TrieNode, TrieSymbol};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
/// Emit Rust source code for the given type and term environments.
|
/// Emit Rust source code for the given type and term environments.
|
||||||
pub fn codegen(typeenv: &TypeEnv, termenv: &TermEnv, tries: &HashMap<TermId, TrieNode>) -> String {
|
pub fn codegen(typeenv: &TypeEnv, termenv: &TermEnv, tries: &BTreeMap<TermId, TrieNode>) -> String {
|
||||||
Codegen::compile(typeenv, termenv, tries).generate_rust()
|
Codegen::compile(typeenv, termenv, tries).generate_rust()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,20 +16,20 @@ pub fn codegen(typeenv: &TypeEnv, termenv: &TermEnv, tries: &HashMap<TermId, Tri
|
|||||||
struct Codegen<'a> {
|
struct Codegen<'a> {
|
||||||
typeenv: &'a TypeEnv,
|
typeenv: &'a TypeEnv,
|
||||||
termenv: &'a TermEnv,
|
termenv: &'a TermEnv,
|
||||||
functions_by_term: &'a HashMap<TermId, TrieNode>,
|
functions_by_term: &'a BTreeMap<TermId, TrieNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
struct BodyContext {
|
struct BodyContext {
|
||||||
/// For each value: (is_ref, ty).
|
/// For each value: (is_ref, ty).
|
||||||
values: HashMap<Value, (bool, TypeId)>,
|
values: BTreeMap<Value, (bool, TypeId)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Codegen<'a> {
|
impl<'a> Codegen<'a> {
|
||||||
fn compile(
|
fn compile(
|
||||||
typeenv: &'a TypeEnv,
|
typeenv: &'a TypeEnv,
|
||||||
termenv: &'a TermEnv,
|
termenv: &'a TermEnv,
|
||||||
tries: &'a HashMap<TermId, TrieNode>,
|
tries: &'a BTreeMap<TermId, TrieNode>,
|
||||||
) -> Codegen<'a> {
|
) -> Codegen<'a> {
|
||||||
Codegen {
|
Codegen {
|
||||||
typeenv,
|
typeenv,
|
||||||
@@ -682,7 +682,7 @@ impl<'a> Codegen<'a> {
|
|||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < edges.len() {
|
while i < edges.len() {
|
||||||
let mut last = i;
|
let mut last = i;
|
||||||
let mut adjacent_variants = HashSet::new();
|
let mut adjacent_variants = BTreeSet::new();
|
||||||
let mut adjacent_variant_input = None;
|
let mut adjacent_variant_input = None;
|
||||||
log::trace!("edge: {:?}", edges[i]);
|
log::trace!("edge: {:?}", edges[i]);
|
||||||
while last < edges.len() {
|
while last < edges.len() {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::lexer::Pos;
|
use crate::lexer::Pos;
|
||||||
use crate::sema::*;
|
use crate::sema::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
declare_id!(
|
declare_id!(
|
||||||
/// The id of an instruction in a `PatternSequence`.
|
/// The id of an instruction in a `PatternSequence`.
|
||||||
@@ -333,7 +333,7 @@ impl PatternSequence {
|
|||||||
typeenv: &TypeEnv,
|
typeenv: &TypeEnv,
|
||||||
termenv: &TermEnv,
|
termenv: &TermEnv,
|
||||||
pat: &Pattern,
|
pat: &Pattern,
|
||||||
vars: &mut HashMap<VarId, Value>,
|
vars: &mut BTreeMap<VarId, Value>,
|
||||||
) {
|
) {
|
||||||
match pat {
|
match pat {
|
||||||
&Pattern::BindPattern(_ty, var, ref subpat) => {
|
&Pattern::BindPattern(_ty, var, ref subpat) => {
|
||||||
@@ -578,7 +578,7 @@ impl ExprSequence {
|
|||||||
typeenv: &TypeEnv,
|
typeenv: &TypeEnv,
|
||||||
termenv: &TermEnv,
|
termenv: &TermEnv,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
vars: &HashMap<VarId, Value>,
|
vars: &BTreeMap<VarId, Value>,
|
||||||
) -> Value {
|
) -> Value {
|
||||||
log::trace!("gen_expr: expr {:?}", expr);
|
log::trace!("gen_expr: expr {:?}", expr);
|
||||||
match expr {
|
match expr {
|
||||||
@@ -651,7 +651,7 @@ pub fn lower_rule(
|
|||||||
expr_seq.pos = termenv.rules[rule.index()].pos;
|
expr_seq.pos = termenv.rules[rule.index()].pos;
|
||||||
|
|
||||||
let ruledata = &termenv.rules[rule.index()];
|
let ruledata = &termenv.rules[rule.index()];
|
||||||
let mut vars = HashMap::new();
|
let mut vars = BTreeMap::new();
|
||||||
let root_term = ruledata
|
let root_term = ruledata
|
||||||
.lhs
|
.lhs
|
||||||
.root_term()
|
.root_term()
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
use crate::ast;
|
use crate::ast;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::lexer::Pos;
|
use crate::lexer::Pos;
|
||||||
use std::collections::HashMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::BTreeSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
declare_id!(
|
declare_id!(
|
||||||
@@ -70,7 +70,7 @@ pub struct TypeEnv {
|
|||||||
pub syms: Vec<String>,
|
pub syms: Vec<String>,
|
||||||
|
|
||||||
/// Map of already-interned symbol names to their `Sym` ids.
|
/// Map of already-interned symbol names to their `Sym` ids.
|
||||||
pub sym_map: HashMap<String, Sym>,
|
pub sym_map: BTreeMap<String, Sym>,
|
||||||
|
|
||||||
/// Arena of type definitions.
|
/// Arena of type definitions.
|
||||||
///
|
///
|
||||||
@@ -78,10 +78,10 @@ pub struct TypeEnv {
|
|||||||
pub types: Vec<Type>,
|
pub types: Vec<Type>,
|
||||||
|
|
||||||
/// A map from a type name symbol to its `TypeId`.
|
/// A map from a type name symbol to its `TypeId`.
|
||||||
pub type_map: HashMap<Sym, TypeId>,
|
pub type_map: BTreeMap<Sym, TypeId>,
|
||||||
|
|
||||||
/// The types of constant symbols.
|
/// The types of constant symbols.
|
||||||
pub const_types: HashMap<Sym, TypeId>,
|
pub const_types: BTreeMap<Sym, TypeId>,
|
||||||
|
|
||||||
/// Type errors that we've found so far during type checking.
|
/// Type errors that we've found so far during type checking.
|
||||||
pub errors: Vec<Error>,
|
pub errors: Vec<Error>,
|
||||||
@@ -181,7 +181,7 @@ pub struct TermEnv {
|
|||||||
pub terms: Vec<Term>,
|
pub terms: Vec<Term>,
|
||||||
|
|
||||||
/// A map from am interned `Term`'s name to its `TermId`.
|
/// A map from am interned `Term`'s name to its `TermId`.
|
||||||
pub term_map: HashMap<Sym, TermId>,
|
pub term_map: BTreeMap<Sym, TermId>,
|
||||||
|
|
||||||
/// Arena of interned rules defined in this ISLE program.
|
/// Arena of interned rules defined in this ISLE program.
|
||||||
///
|
///
|
||||||
@@ -544,10 +544,10 @@ impl TypeEnv {
|
|||||||
filenames: defs.filenames.clone(),
|
filenames: defs.filenames.clone(),
|
||||||
file_texts: defs.file_texts.clone(),
|
file_texts: defs.file_texts.clone(),
|
||||||
syms: vec![],
|
syms: vec![],
|
||||||
sym_map: HashMap::new(),
|
sym_map: BTreeMap::new(),
|
||||||
types: vec![],
|
types: vec![],
|
||||||
type_map: HashMap::new(),
|
type_map: BTreeMap::new(),
|
||||||
const_types: HashMap::new(),
|
const_types: BTreeMap::new(),
|
||||||
errors: vec![],
|
errors: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -753,7 +753,7 @@ impl TermEnv {
|
|||||||
pub fn from_ast(tyenv: &mut TypeEnv, defs: &ast::Defs) -> Result<TermEnv> {
|
pub fn from_ast(tyenv: &mut TypeEnv, defs: &ast::Defs) -> Result<TermEnv> {
|
||||||
let mut env = TermEnv {
|
let mut env = TermEnv {
|
||||||
terms: vec![],
|
terms: vec![],
|
||||||
term_map: HashMap::new(),
|
term_map: BTreeMap::new(),
|
||||||
rules: vec![],
|
rules: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -935,7 +935,7 @@ impl TermEnv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn collect_extractor_templates(&mut self, tyenv: &mut TypeEnv, defs: &ast::Defs) {
|
fn collect_extractor_templates(&mut self, tyenv: &mut TypeEnv, defs: &ast::Defs) {
|
||||||
let mut extractor_call_graph = HashMap::new();
|
let mut extractor_call_graph = BTreeMap::new();
|
||||||
|
|
||||||
for def in &defs.defs {
|
for def in &defs.defs {
|
||||||
if let &ast::Def::Extractor(ref ext) = def {
|
if let &ast::Def::Extractor(ref ext) = def {
|
||||||
@@ -954,7 +954,7 @@ impl TermEnv {
|
|||||||
let template = ext.template.make_macro_template(&ext.args[..]);
|
let template = ext.template.make_macro_template(&ext.args[..]);
|
||||||
log::trace!("extractor def: {:?} becomes template {:?}", def, template);
|
log::trace!("extractor def: {:?} becomes template {:?}", def, template);
|
||||||
|
|
||||||
let mut callees = HashSet::new();
|
let mut callees = BTreeSet::new();
|
||||||
template.terms(&mut |pos, t| {
|
template.terms(&mut |pos, t| {
|
||||||
let t = tyenv.intern_mut(t);
|
let t = tyenv.intern_mut(t);
|
||||||
callees.insert(t);
|
callees.insert(t);
|
||||||
@@ -1008,7 +1008,7 @@ impl TermEnv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for cycles in the extractor call graph.
|
// Check for cycles in the extractor call graph.
|
||||||
let mut seen = HashSet::new();
|
let mut seen = BTreeSet::new();
|
||||||
let mut stack = vec![];
|
let mut stack = vec![];
|
||||||
'outer: for root in extractor_call_graph.keys().copied() {
|
'outer: for root in extractor_call_graph.keys().copied() {
|
||||||
seen.clear();
|
seen.clear();
|
||||||
@@ -1828,7 +1828,7 @@ impl TermEnv {
|
|||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ast::Ident;
|
use crate::ast::Ident;
|
||||||
use crate::lexer::Lexer;
|
use crate::lexer::{Lexer, Pos};
|
||||||
use crate::parser::parse;
|
use crate::parser::parse;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1868,51 +1868,62 @@ mod test {
|
|||||||
assert_eq!(tyenv.type_map.get(&sym_u32).unwrap(), &TypeId(0));
|
assert_eq!(tyenv.type_map.get(&sym_u32).unwrap(), &TypeId(0));
|
||||||
assert_eq!(tyenv.type_map.get(&sym_a).unwrap(), &TypeId(1));
|
assert_eq!(tyenv.type_map.get(&sym_a).unwrap(), &TypeId(1));
|
||||||
|
|
||||||
assert_eq!(
|
let expected_types = vec![
|
||||||
tyenv.types,
|
Type::Primitive(
|
||||||
vec![
|
TypeId(0),
|
||||||
Type::Primitive(TypeId(0), sym_u32),
|
sym_u32,
|
||||||
Type::Enum {
|
Pos {
|
||||||
name: sym_a,
|
file: 0,
|
||||||
id: TypeId(1),
|
offset: 19,
|
||||||
is_extern: true,
|
line: 2,
|
||||||
variants: vec![
|
col: 0,
|
||||||
Variant {
|
},
|
||||||
name: sym_b,
|
),
|
||||||
fullname: sym_a_b,
|
Type::Enum {
|
||||||
id: VariantId(0),
|
name: sym_a,
|
||||||
fields: vec![
|
id: TypeId(1),
|
||||||
Field {
|
is_extern: true,
|
||||||
name: sym_f1,
|
variants: vec![
|
||||||
id: FieldId(0),
|
Variant {
|
||||||
ty: TypeId(0),
|
name: sym_b,
|
||||||
},
|
fullname: sym_a_b,
|
||||||
Field {
|
id: VariantId(0),
|
||||||
name: sym_f2,
|
fields: vec![
|
||||||
id: FieldId(1),
|
Field {
|
||||||
ty: TypeId(0),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
Variant {
|
|
||||||
name: sym_c,
|
|
||||||
fullname: sym_a_c,
|
|
||||||
id: VariantId(1),
|
|
||||||
fields: vec![Field {
|
|
||||||
name: sym_f1,
|
name: sym_f1,
|
||||||
id: FieldId(0),
|
id: FieldId(0),
|
||||||
ty: TypeId(0),
|
ty: TypeId(0),
|
||||||
},],
|
},
|
||||||
},
|
Field {
|
||||||
],
|
name: sym_f2,
|
||||||
pos: Pos {
|
id: FieldId(1),
|
||||||
file: 0,
|
ty: TypeId(0),
|
||||||
offset: 58,
|
},
|
||||||
line: 3,
|
],
|
||||||
col: 18,
|
|
||||||
},
|
},
|
||||||
|
Variant {
|
||||||
|
name: sym_c,
|
||||||
|
fullname: sym_a_c,
|
||||||
|
id: VariantId(1),
|
||||||
|
fields: vec![Field {
|
||||||
|
name: sym_f1,
|
||||||
|
id: FieldId(0),
|
||||||
|
ty: TypeId(0),
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
pos: Pos {
|
||||||
|
file: 0,
|
||||||
|
offset: 58,
|
||||||
|
line: 3,
|
||||||
|
col: 0,
|
||||||
},
|
},
|
||||||
]
|
},
|
||||||
);
|
];
|
||||||
|
|
||||||
|
assert_eq!(tyenv.types.len(), expected_types.len());
|
||||||
|
for (i, (actual, expected)) in tyenv.types.iter().zip(&expected_types).enumerate() {
|
||||||
|
assert_eq!(expected, actual, "`{}`th type is not equal!", i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
use crate::ir::{lower_rule, ExprSequence, PatternInst, PatternSequence};
|
use crate::ir::{lower_rule, ExprSequence, PatternInst, PatternSequence};
|
||||||
use crate::sema::{RuleId, TermEnv, TermId, TypeEnv};
|
use crate::sema::{RuleId, TermEnv, TermId, TypeEnv};
|
||||||
use std::collections::HashMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
/// Construct the tries for each term.
|
/// Construct the tries for each term.
|
||||||
pub fn build_tries(typeenv: &TypeEnv, termenv: &TermEnv) -> HashMap<TermId, TrieNode> {
|
pub fn build_tries(typeenv: &TypeEnv, termenv: &TermEnv) -> BTreeMap<TermId, TrieNode> {
|
||||||
let mut builder = TermFunctionsBuilder::new(typeenv, termenv);
|
let mut builder = TermFunctionsBuilder::new(typeenv, termenv);
|
||||||
builder.build();
|
builder.build();
|
||||||
log::trace!("builder: {:?}", builder);
|
log::trace!("builder: {:?}", builder);
|
||||||
@@ -511,7 +511,7 @@ impl TermFunctionBuilder {
|
|||||||
struct TermFunctionsBuilder<'a> {
|
struct TermFunctionsBuilder<'a> {
|
||||||
typeenv: &'a TypeEnv,
|
typeenv: &'a TypeEnv,
|
||||||
termenv: &'a TermEnv,
|
termenv: &'a TermEnv,
|
||||||
builders_by_term: HashMap<TermId, TermFunctionBuilder>,
|
builders_by_term: BTreeMap<TermId, TermFunctionBuilder>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TermFunctionsBuilder<'a> {
|
impl<'a> TermFunctionsBuilder<'a> {
|
||||||
@@ -519,7 +519,7 @@ impl<'a> TermFunctionsBuilder<'a> {
|
|||||||
log::trace!("typeenv: {:?}", typeenv);
|
log::trace!("typeenv: {:?}", typeenv);
|
||||||
log::trace!("termenv: {:?}", termenv);
|
log::trace!("termenv: {:?}", termenv);
|
||||||
Self {
|
Self {
|
||||||
builders_by_term: HashMap::new(),
|
builders_by_term: BTreeMap::new(),
|
||||||
typeenv,
|
typeenv,
|
||||||
termenv,
|
termenv,
|
||||||
}
|
}
|
||||||
@@ -546,12 +546,12 @@ impl<'a> TermFunctionsBuilder<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finalize(self) -> HashMap<TermId, TrieNode> {
|
fn finalize(self) -> BTreeMap<TermId, TrieNode> {
|
||||||
let functions_by_term = self
|
let functions_by_term = self
|
||||||
.builders_by_term
|
.builders_by_term
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(term, builder)| (term, builder.trie))
|
.map(|(term, builder)| (term, builder.trie))
|
||||||
.collect::<HashMap<_, _>>();
|
.collect::<BTreeMap<_, _>>();
|
||||||
functions_by_term
|
functions_by_term
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user