mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
simple literals in editor ast
This commit is contained in:
parent
a174137351
commit
8b289f3398
6 changed files with 291 additions and 8 deletions
|
@ -1486,7 +1486,7 @@ fn flatten_str_literal<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
||||||
match expr {
|
match expr {
|
||||||
ast::Expr::Var { .. } => true,
|
ast::Expr::Var { .. } => true,
|
||||||
ast::Expr::Access(sub_expr, _) => is_valid_interpolation(sub_expr),
|
ast::Expr::Access(sub_expr, _) => is_valid_interpolation(sub_expr),
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub struct Region {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Region {
|
impl Region {
|
||||||
pub fn zero() -> Self {
|
pub const fn zero() -> Self {
|
||||||
Region {
|
Region {
|
||||||
start_line: 0,
|
start_line: 0,
|
||||||
end_line: 0,
|
end_line: 0,
|
||||||
|
|
|
@ -24,6 +24,18 @@ pub enum IntStyle {
|
||||||
Binary,
|
Binary,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IntStyle {
|
||||||
|
pub fn from_base(base: roc_parse::ast::Base) -> Self {
|
||||||
|
use roc_parse::ast::Base;
|
||||||
|
match base {
|
||||||
|
Base::Decimal => Self::Decimal,
|
||||||
|
Base::Octal => Self::Octal,
|
||||||
|
Base::Hex => Self::Hex,
|
||||||
|
Base::Binary => Self::Binary,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum IntVal {
|
pub enum IntVal {
|
||||||
I64(i64),
|
I64(i64),
|
||||||
|
@ -237,11 +249,7 @@ pub struct PatId {
|
||||||
slot: ExprPoolSlot, // TODO PatPoolSlot
|
slot: ExprPoolSlot, // TODO PatPoolSlot
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
pub type ExprId = NodeId<Expr2>;
|
||||||
pub struct ExprId {
|
|
||||||
page_id: ExprPoolId,
|
|
||||||
slot: ExprPoolSlot,
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have a maximum of 65K pages.
|
// We have a maximum of 65K pages.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
|
|
@ -0,0 +1,274 @@
|
||||||
|
use crate::ast::{Expr2, ExprId, FloatVal, IntStyle, IntVal};
|
||||||
|
use crate::pool::{Pool, PoolStr, PoolVec};
|
||||||
|
use roc_can::expr::Output;
|
||||||
|
use roc_can::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int};
|
||||||
|
use roc_can::scope::Scope;
|
||||||
|
use roc_module::low_level::LowLevel;
|
||||||
|
use roc_module::operator::CalledVia;
|
||||||
|
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
||||||
|
use roc_parse::ast::StrLiteral;
|
||||||
|
use roc_region::all::{Located, Region};
|
||||||
|
use roc_types::subs::{VarStore, Variable};
|
||||||
|
|
||||||
|
pub struct Env<'a> {
|
||||||
|
var_store: VarStore,
|
||||||
|
problems: Vec<()>,
|
||||||
|
pool: Pool,
|
||||||
|
module_ids: &'a ModuleIds,
|
||||||
|
}
|
||||||
|
|
||||||
|
const ZERO: Region = Region::zero();
|
||||||
|
|
||||||
|
pub fn from_parse_expr<'a>(
|
||||||
|
env: &mut Env<'a>,
|
||||||
|
scope: &mut Scope,
|
||||||
|
parse_expr: &'a roc_parse::ast::Expr<'a>,
|
||||||
|
) -> (crate::ast::ExprId, Output) {
|
||||||
|
use roc_parse::ast::Expr::*;
|
||||||
|
match parse_expr {
|
||||||
|
Float(string) => {
|
||||||
|
match finish_parsing_float(string) {
|
||||||
|
Ok(float) => {
|
||||||
|
let expr = Expr2::Float {
|
||||||
|
number: FloatVal::F64(float),
|
||||||
|
var: env.var_store.fresh(),
|
||||||
|
};
|
||||||
|
|
||||||
|
(env.pool.add(expr), Output::default())
|
||||||
|
}
|
||||||
|
Err((_raw, _error)) => {
|
||||||
|
// emit runtime error
|
||||||
|
// let runtime_error = InvalidFloat(error, ZERO, raw.into());
|
||||||
|
//
|
||||||
|
// env.problem(Problem::RuntimeError(runtime_error.clone()));
|
||||||
|
//
|
||||||
|
// Expr::RuntimeError(runtime_error)
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Num(string) => {
|
||||||
|
match finish_parsing_int(string) {
|
||||||
|
Ok(int) => {
|
||||||
|
let expr = Expr2::SmallInt {
|
||||||
|
number: IntVal::I64(int),
|
||||||
|
var: env.var_store.fresh(),
|
||||||
|
// TODO non-hardcode
|
||||||
|
style: IntStyle::Decimal,
|
||||||
|
text: PoolStr::new(string, &mut env.pool),
|
||||||
|
};
|
||||||
|
|
||||||
|
(env.pool.add(expr), Output::default())
|
||||||
|
}
|
||||||
|
Err((_raw, _error)) => {
|
||||||
|
// emit runtime error
|
||||||
|
// let runtime_error = InvalidFloat(error, ZERO, raw.into());
|
||||||
|
//
|
||||||
|
// env.problem(Problem::RuntimeError(runtime_error.clone()));
|
||||||
|
//
|
||||||
|
// Expr::RuntimeError(runtime_error)
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NonBase10Int {
|
||||||
|
string,
|
||||||
|
base,
|
||||||
|
is_negative,
|
||||||
|
} => {
|
||||||
|
match finish_parsing_base(string, *base, *is_negative) {
|
||||||
|
Ok(int) => {
|
||||||
|
let expr = Expr2::SmallInt {
|
||||||
|
number: IntVal::I64(int),
|
||||||
|
var: env.var_store.fresh(),
|
||||||
|
// TODO non-hardcode
|
||||||
|
style: IntStyle::from_base(*base),
|
||||||
|
text: PoolStr::new(string, &mut env.pool),
|
||||||
|
};
|
||||||
|
|
||||||
|
(env.pool.add(expr), Output::default())
|
||||||
|
}
|
||||||
|
Err((_raw, _error)) => {
|
||||||
|
// emit runtime error
|
||||||
|
// let runtime_error = InvalidFloat(error, ZERO, raw.into());
|
||||||
|
//
|
||||||
|
// env.problem(Problem::RuntimeError(runtime_error.clone()));
|
||||||
|
//
|
||||||
|
// Expr::RuntimeError(runtime_error)
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Str(literal) => flatten_str_literal(env, scope, &literal),
|
||||||
|
|
||||||
|
// /// string literals of length up to 30B
|
||||||
|
// SmallStr(ArrayString<U30>), // 31B
|
||||||
|
// /// string literals of length 31B or more
|
||||||
|
// Str(PoolStr), // 8B
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flatten_str_literal<'a>(
|
||||||
|
env: &mut Env<'a>,
|
||||||
|
scope: &mut Scope,
|
||||||
|
literal: &StrLiteral<'a>,
|
||||||
|
) -> (ExprId, Output) {
|
||||||
|
use roc_parse::ast::StrLiteral::*;
|
||||||
|
|
||||||
|
match literal {
|
||||||
|
PlainLine(str_slice) => {
|
||||||
|
// TODO use smallstr
|
||||||
|
let expr = Expr2::Str(PoolStr::new(str_slice, &mut env.pool));
|
||||||
|
|
||||||
|
(env.pool.add(expr), Output::default())
|
||||||
|
}
|
||||||
|
Line(segments) => flatten_str_lines(env, scope, &[segments]),
|
||||||
|
Block(lines) => flatten_str_lines(env, scope, lines),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum StrSegment {
|
||||||
|
Interpolation(ExprId),
|
||||||
|
Plaintext(PoolStr),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flatten_str_lines<'a>(
|
||||||
|
env: &mut Env<'a>,
|
||||||
|
scope: &mut Scope,
|
||||||
|
lines: &[&[roc_parse::ast::StrSegment<'a>]],
|
||||||
|
) -> (ExprId, Output) {
|
||||||
|
use roc_parse::ast::StrSegment::*;
|
||||||
|
|
||||||
|
let mut buf = String::new();
|
||||||
|
let mut segments = Vec::new();
|
||||||
|
let mut output = Output::default();
|
||||||
|
|
||||||
|
for line in lines {
|
||||||
|
for segment in line.iter() {
|
||||||
|
match segment {
|
||||||
|
Plaintext(string) => {
|
||||||
|
buf.push_str(string);
|
||||||
|
}
|
||||||
|
Unicode(loc_hex_digits) => match u32::from_str_radix(loc_hex_digits.value, 16) {
|
||||||
|
Ok(code_pt) => match std::char::from_u32(code_pt) {
|
||||||
|
Some(ch) => {
|
||||||
|
buf.push(ch);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// env.problem(Problem::InvalidUnicodeCodePoint(loc_hex_digits.region));
|
||||||
|
//
|
||||||
|
// return (
|
||||||
|
// Expr::RuntimeError(RuntimeError::InvalidUnicodeCodePoint(
|
||||||
|
// loc_hex_digits.region,
|
||||||
|
// )),
|
||||||
|
// output,
|
||||||
|
// );
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
// env.problem(Problem::InvalidHexadecimal(loc_hex_digits.region));
|
||||||
|
//
|
||||||
|
// return (
|
||||||
|
// Expr::RuntimeError(RuntimeError::InvalidHexadecimal(
|
||||||
|
// loc_hex_digits.region,
|
||||||
|
// )),
|
||||||
|
// output,
|
||||||
|
// );
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Interpolated(loc_expr) => {
|
||||||
|
if roc_can::expr::is_valid_interpolation(loc_expr.value) {
|
||||||
|
// Interpolations desugar to Str.concat calls
|
||||||
|
output.references.calls.insert(Symbol::STR_CONCAT);
|
||||||
|
|
||||||
|
if !buf.is_empty() {
|
||||||
|
segments.push(StrSegment::Plaintext(PoolStr::new(&buf, &mut env.pool)));
|
||||||
|
|
||||||
|
buf = String::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
let (loc_expr, new_output) = from_parse_expr(env, scope, loc_expr.value);
|
||||||
|
|
||||||
|
output.union(new_output);
|
||||||
|
|
||||||
|
segments.push(StrSegment::Interpolation(loc_expr));
|
||||||
|
} else {
|
||||||
|
// env.problem(Problem::InvalidInterpolation(loc_expr.region));
|
||||||
|
//
|
||||||
|
// return (
|
||||||
|
// Expr::RuntimeError(RuntimeError::InvalidInterpolation(loc_expr.region)),
|
||||||
|
// output,
|
||||||
|
// );
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EscapedChar(escaped) => buf.push(roc_can::expr::unescape_char(escaped)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !buf.is_empty() {
|
||||||
|
segments.push(StrSegment::Plaintext(PoolStr::new(&buf, &mut env.pool)));
|
||||||
|
}
|
||||||
|
|
||||||
|
(desugar_str_segments(env, segments), output)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolve stirng interpolations by desugaring a sequence of StrSegments
|
||||||
|
/// into nested calls to Str.concat
|
||||||
|
fn desugar_str_segments<'a>(env: &mut Env<'a>, segments: Vec<StrSegment>) -> ExprId {
|
||||||
|
use StrSegment::*;
|
||||||
|
|
||||||
|
let pool = &mut env.pool;
|
||||||
|
let var_store = &mut env.var_store;
|
||||||
|
|
||||||
|
let mut iter = segments.into_iter().rev();
|
||||||
|
let mut expr_id = match iter.next() {
|
||||||
|
Some(Plaintext(pool_str)) => {
|
||||||
|
let expr = Expr2::Str(pool_str);
|
||||||
|
|
||||||
|
pool.add(expr)
|
||||||
|
}
|
||||||
|
Some(Interpolation(expr_id)) => expr_id,
|
||||||
|
None => {
|
||||||
|
// No segments? Empty string!
|
||||||
|
|
||||||
|
let pool_str = PoolStr::new("", pool);
|
||||||
|
let expr = Expr2::Str(pool_str);
|
||||||
|
|
||||||
|
pool.add(expr)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for seg in iter {
|
||||||
|
let new_expr_id = match seg {
|
||||||
|
Plaintext(string) => pool.add(Expr2::Str(string)),
|
||||||
|
Interpolation(expr_id) => expr_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
let concat_expr_id = pool.add(Expr2::Var(Symbol::STR_CONCAT));
|
||||||
|
|
||||||
|
let args = vec![
|
||||||
|
(var_store.fresh(), new_expr_id),
|
||||||
|
(var_store.fresh(), expr_id),
|
||||||
|
];
|
||||||
|
let args = PoolVec::new(args.into_iter(), pool);
|
||||||
|
|
||||||
|
let expr = Expr2::Call {
|
||||||
|
args,
|
||||||
|
expr: concat_expr_id,
|
||||||
|
expr_var: var_store.fresh(),
|
||||||
|
fn_var: var_store.fresh(),
|
||||||
|
closure_var: var_store.fresh(),
|
||||||
|
called_via: CalledVia::Space,
|
||||||
|
};
|
||||||
|
|
||||||
|
expr_id = pool.add(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_id
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ use winit::event_loop::ControlFlow;
|
||||||
|
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
mod buffer;
|
mod buffer;
|
||||||
|
pub mod expr;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
mod keyboard_input;
|
mod keyboard_input;
|
||||||
pub mod pool;
|
pub mod pool;
|
||||||
|
|
|
@ -228,7 +228,7 @@ fn pool_vec_size() {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: 'a + Sized> PoolVec<T> {
|
impl<'a, T: 'a + Sized> PoolVec<T> {
|
||||||
pub fn new<I: ExactSizeIterator<Item = T>, S>(nodes: I, pool: &mut Pool) -> Self {
|
pub fn new<I: ExactSizeIterator<Item = T>>(nodes: I, pool: &mut Pool) -> Self {
|
||||||
debug_assert!(nodes.len() <= u32::MAX as usize);
|
debug_assert!(nodes.len() <= u32::MAX as usize);
|
||||||
debug_assert!(size_of::<T>() <= NODE_BYTES);
|
debug_assert!(size_of::<T>() <= NODE_BYTES);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue