CHECKPOINT: Initial syntax arbitrary implementation.
This commit is contained in:
@@ -32,6 +32,7 @@ thiserror = "1.0.57"
|
|||||||
anyhow = "1.0.80"
|
anyhow = "1.0.80"
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["time", "json", "env-filter"] }
|
tracing-subscriber = { version = "0.3.18", features = ["time", "json", "env-filter"] }
|
||||||
|
names = "0.14.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
lalrpop = "0.20.2"
|
lalrpop = "0.20.2"
|
||||||
|
|||||||
23
src/bin/gen_program.rs
Normal file
23
src/bin/gen_program.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
use ngr::syntax::ProgramGenerator;
|
||||||
|
use ngr::util::pretty::Allocator;
|
||||||
|
use proptest::strategy::{Strategy, ValueTree};
|
||||||
|
use proptest::test_runner::{Config, TestRunner};
|
||||||
|
|
||||||
|
fn main() -> Result<(), anyhow::Error> {
|
||||||
|
let generator = ProgramGenerator::default();
|
||||||
|
let runner_config = Config::default();
|
||||||
|
let mut runner = TestRunner::new(runner_config);
|
||||||
|
let program_tree = generator
|
||||||
|
.new_tree(&mut runner)
|
||||||
|
.map_err(|e| anyhow::anyhow!("Couldn't generate test program: {}", e))?;
|
||||||
|
let program = program_tree.current();
|
||||||
|
let allocator = Allocator::new();
|
||||||
|
let mut stdout = std::io::stdout();
|
||||||
|
|
||||||
|
for top_level in program.into_iter() {
|
||||||
|
let docbuilder = top_level.pretty(&allocator);
|
||||||
|
docbuilder.render(78, &mut stdout)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -43,6 +43,7 @@ lalrpop_mod!(
|
|||||||
pub mod pretty;
|
pub mod pretty;
|
||||||
mod validate;
|
mod validate;
|
||||||
|
|
||||||
|
pub use crate::syntax::arbitrary::ProgramGenerator;
|
||||||
pub use crate::syntax::ast::*;
|
pub use crate::syntax::ast::*;
|
||||||
pub use crate::syntax::location::Location;
|
pub use crate::syntax::location::Location;
|
||||||
pub use crate::syntax::name::Name;
|
pub use crate::syntax::name::Name;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -76,7 +76,7 @@ impl StructureDefinition {
|
|||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum TopLevel {
|
pub enum TopLevel {
|
||||||
Expression(Expression),
|
Expression(Expression),
|
||||||
Structure(Location, Name, Vec<(Name, Type)>),
|
Structure(Location, Name, Vec<(Name, Option<Type>)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Located for TopLevel {
|
impl Located for TopLevel {
|
||||||
@@ -205,6 +205,8 @@ pub enum Value {
|
|||||||
/// operation "-" on the number 4. We'll translate this into a type-specific
|
/// operation "-" on the number 4. We'll translate this into a type-specific
|
||||||
/// number at a later time.
|
/// number at a later time.
|
||||||
Number(Option<u8>, Option<ConstantType>, u64),
|
Number(Option<u8>, Option<ConstantType>, u64),
|
||||||
|
/// The empty value
|
||||||
|
Void,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ impl Expression {
|
|||||||
Some(ConstantType::U32) => Ok(Value::U32(*v as u32)),
|
Some(ConstantType::U32) => Ok(Value::U32(*v as u32)),
|
||||||
Some(ConstantType::U64) => Ok(Value::U64(*v)),
|
Some(ConstantType::U64) => Ok(Value::U64(*v)),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
super::Value::Void => Ok(Value::Void),
|
||||||
},
|
},
|
||||||
|
|
||||||
Expression::Constructor(_, on, fields) => {
|
Expression::Constructor(_, on, fields) => {
|
||||||
|
|||||||
@@ -92,9 +92,12 @@ Structure: TopLevel = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Field: (Name, Type) = {
|
Field: (Name, Option<Type>) = {
|
||||||
<s:@L> <name:"<var>"> <e:@L> ":" <field_type: Type> ";" =>
|
<s:@L> <name:"<var>"> <e:@L> ":" <field_type: Type> ";" =>
|
||||||
(Name::new(name, Location::new(file_idx, s..e)), field_type)
|
(Name::new(name, Location::new(file_idx, s..e)), Some(field_type)),
|
||||||
|
<s:@L> <name:"<var>"> <e:@L> ";" =>
|
||||||
|
(Name::new(name, Location::new(file_idx, s..e)), None),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Type: Type = {
|
Type: Type = {
|
||||||
|
|||||||
@@ -84,7 +84,10 @@ impl Program {
|
|||||||
impl TopLevel {
|
impl TopLevel {
|
||||||
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
|
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
|
||||||
match self {
|
match self {
|
||||||
TopLevel::Expression(expr) => expr.pretty(allocator),
|
TopLevel::Expression(expr) => expr
|
||||||
|
.pretty(allocator)
|
||||||
|
.append(allocator.text(";"))
|
||||||
|
.append(allocator.hardline()),
|
||||||
TopLevel::Structure(_, name, fields) => allocator
|
TopLevel::Structure(_, name, fields) => allocator
|
||||||
.text("struct")
|
.text("struct")
|
||||||
.append(allocator.space())
|
.append(allocator.space())
|
||||||
@@ -95,17 +98,24 @@ impl TopLevel {
|
|||||||
.append(
|
.append(
|
||||||
allocator
|
allocator
|
||||||
.concat(fields.iter().map(|(name, ty)| {
|
.concat(fields.iter().map(|(name, ty)| {
|
||||||
|
let type_bit = if let Some(ty) = ty {
|
||||||
allocator
|
allocator
|
||||||
.text(name.to_string())
|
.text(":")
|
||||||
.append(allocator.text(":"))
|
|
||||||
.append(allocator.space())
|
.append(allocator.space())
|
||||||
.append(ty.pretty(allocator))
|
.append(ty.pretty(allocator))
|
||||||
|
} else {
|
||||||
|
allocator.nil()
|
||||||
|
};
|
||||||
|
allocator
|
||||||
|
.text(name.to_string())
|
||||||
|
.append(type_bit)
|
||||||
.append(allocator.text(";"))
|
.append(allocator.text(";"))
|
||||||
.append(allocator.hardline())
|
.append(allocator.hardline())
|
||||||
}))
|
}))
|
||||||
.nest(2),
|
.nest(2),
|
||||||
)
|
)
|
||||||
.append(allocator.text("}")),
|
.append(allocator.text("}"))
|
||||||
|
.append(allocator.hardline()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,6 +241,8 @@ impl Value {
|
|||||||
|
|
||||||
allocator.text(value_str)
|
allocator.text(value_str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value::Void => allocator.text("<void>"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use internment::ArcIntern;
|
use internment::ArcIntern;
|
||||||
use logos::{Lexer, Logos};
|
use logos::{Lexer, Logos};
|
||||||
use std::fmt;
|
use std::{fmt, str::FromStr};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// A single token of the input stream; used to help the parsing go down
|
/// A single token of the input stream; used to help the parsing go down
|
||||||
@@ -205,6 +205,43 @@ impl From<ConstantType> for cranelift_codegen::ir::Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct StringNotConstantType();
|
||||||
|
|
||||||
|
impl FromStr for ConstantType {
|
||||||
|
type Err = StringNotConstantType;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"i8" => Ok(ConstantType::I8),
|
||||||
|
"i16" => Ok(ConstantType::I16),
|
||||||
|
"i32" => Ok(ConstantType::I32),
|
||||||
|
"i64" => Ok(ConstantType::I64),
|
||||||
|
"u8" => Ok(ConstantType::U8),
|
||||||
|
"u16" => Ok(ConstantType::U16),
|
||||||
|
"u32" => Ok(ConstantType::U32),
|
||||||
|
"u64" => Ok(ConstantType::U64),
|
||||||
|
"void" => Ok(ConstantType::Void),
|
||||||
|
_ => Err(StringNotConstantType()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ConstantType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
ConstantType::I8 => write!(f, "i8"),
|
||||||
|
ConstantType::I16 => write!(f, "i16"),
|
||||||
|
ConstantType::I32 => write!(f, "i32"),
|
||||||
|
ConstantType::I64 => write!(f, "i64"),
|
||||||
|
ConstantType::U8 => write!(f, "u8"),
|
||||||
|
ConstantType::U16 => write!(f, "u16"),
|
||||||
|
ConstantType::U32 => write!(f, "u32"),
|
||||||
|
ConstantType::U64 => write!(f, "u64"),
|
||||||
|
ConstantType::Void => write!(f, "void"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ConstantType {
|
impl ConstantType {
|
||||||
/// Return the set of types that can be safely casted into this type.
|
/// Return the set of types that can be safely casted into this type.
|
||||||
pub fn safe_casts_to(self) -> Vec<ConstantType> {
|
pub fn safe_casts_to(self) -> Vec<ConstantType> {
|
||||||
@@ -268,6 +305,32 @@ impl ConstantType {
|
|||||||
ConstantType::U64 => "u64".to_string(),
|
ConstantType::U64 => "u64".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the set of all primitives that can return this
|
||||||
|
/// type, along with the argument types for those primitives.
|
||||||
|
///
|
||||||
|
/// A "None" value as an argument type means that the argument
|
||||||
|
/// type is unconstrained by the return type.
|
||||||
|
pub fn primitives_for(&self) -> Vec<(crate::ir::Primitive, Vec<Option<ConstantType>>)> {
|
||||||
|
use crate::ir::Primitive::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
ConstantType::Void => vec![(Print, vec![None])],
|
||||||
|
ConstantType::I8 | ConstantType::I16 | ConstantType::I32 | ConstantType::I64 => vec![
|
||||||
|
(Plus, vec![Some(*self), Some(*self)]),
|
||||||
|
(Minus, vec![Some(*self), Some(*self)]),
|
||||||
|
(Times, vec![Some(*self), Some(*self)]),
|
||||||
|
(Divide, vec![Some(*self), Some(*self)]),
|
||||||
|
(Negate, vec![Some(*self)]),
|
||||||
|
],
|
||||||
|
ConstantType::U8 | ConstantType::U16 | ConstantType::U32 | ConstantType::U64 => vec![
|
||||||
|
(Plus, vec![Some(*self), Some(*self)]),
|
||||||
|
(Minus, vec![Some(*self), Some(*self)]),
|
||||||
|
(Times, vec![Some(*self), Some(*self)]),
|
||||||
|
(Divide, vec![Some(*self), Some(*self)]),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error, PartialEq)]
|
#[derive(Debug, Error, PartialEq)]
|
||||||
|
|||||||
@@ -99,11 +99,8 @@ impl Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TopLevel::Structure(loc, name, fields) => {
|
TopLevel::Structure(loc, name, fields) => {
|
||||||
let definition = StructureDefinition::new(
|
let definition =
|
||||||
loc,
|
StructureDefinition::new(loc, name.clone(), fields.into_iter().collect());
|
||||||
name.clone(),
|
|
||||||
fields.into_iter().map(|(n, t)| (n, Some(t))).collect(),
|
|
||||||
);
|
|
||||||
|
|
||||||
structures.insert(name, definition);
|
structures.insert(name, definition);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,6 +124,14 @@ impl InferenceEngine {
|
|||||||
// converting values is mostly tedious, because there's so many cases
|
// converting values is mostly tedious, because there's so many cases
|
||||||
// involved
|
// involved
|
||||||
syntax::Expression::Value(loc, val) => match val {
|
syntax::Expression::Value(loc, val) => match val {
|
||||||
|
syntax::Value::Void => (
|
||||||
|
ir::Expression::Atomic(ir::ValueOrRef::Value(
|
||||||
|
loc,
|
||||||
|
ir::TypeOrVar::Primitive(PrimitiveType::Void),
|
||||||
|
ir::Value::Void,
|
||||||
|
)),
|
||||||
|
ir::TypeOrVar::Primitive(PrimitiveType::Void),
|
||||||
|
),
|
||||||
syntax::Value::Number(base, mctype, value) => {
|
syntax::Value::Number(base, mctype, value) => {
|
||||||
let (newval, newtype) = match mctype {
|
let (newval, newtype) = match mctype {
|
||||||
None => {
|
None => {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
pub mod pretty;
|
pub mod pretty;
|
||||||
pub mod scoped_map;
|
pub mod scoped_map;
|
||||||
pub mod warning_result;
|
pub mod warning_result;
|
||||||
|
pub mod weighted_map;
|
||||||
|
|||||||
21
src/util/weighted_map.rs
Normal file
21
src/util/weighted_map.rs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
use rand::distributions::{Distribution, WeightedIndex};
|
||||||
|
|
||||||
|
pub struct WeightedMap<T: Clone> {
|
||||||
|
index: WeightedIndex<usize>,
|
||||||
|
items: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> WeightedMap<T> {
|
||||||
|
pub fn new(map: &[(usize, T)]) -> Self {
|
||||||
|
let index = WeightedIndex::new(map.iter().map(|x| x.0)).unwrap();
|
||||||
|
let items = map.iter().map(|x| x.1.clone()).collect();
|
||||||
|
WeightedMap { index, items }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> Distribution<T> for WeightedMap<T> {
|
||||||
|
fn sample<R: rand::prelude::Rng + ?Sized>(&self, rng: &mut R) -> T {
|
||||||
|
let idx = self.index.sample(rng);
|
||||||
|
self.items.get(idx).unwrap().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user