mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 13:59:08 +00:00
Constrain string interpolation
This commit is contained in:
parent
5080a7e24b
commit
274e7e786d
11 changed files with 150 additions and 180 deletions
|
@ -9,12 +9,13 @@ use crate::num::{
|
||||||
use crate::pattern::{canonicalize_pattern, Pattern};
|
use crate::pattern::{canonicalize_pattern, Pattern};
|
||||||
use crate::procedure::References;
|
use crate::procedure::References;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
|
use inlinable_string::InlinableString;
|
||||||
use roc_collections::all::{ImSet, MutMap, MutSet, SendMap};
|
use roc_collections::all::{ImSet, MutMap, MutSet, SendMap};
|
||||||
use roc_module::ident::{Lowercase, TagName};
|
use roc_module::ident::{Lowercase, TagName};
|
||||||
use roc_module::low_level::LowLevel;
|
use roc_module::low_level::LowLevel;
|
||||||
use roc_module::operator::CalledVia;
|
use roc_module::operator::CalledVia;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_parse::ast::{self, StrLiteral, StrSegment};
|
use roc_parse::ast::{self, StrLiteral};
|
||||||
use roc_parse::pattern::PatternType::*;
|
use roc_parse::pattern::PatternType::*;
|
||||||
use roc_problem::can::{PrecedenceProblem, Problem, RuntimeError};
|
use roc_problem::can::{PrecedenceProblem, Problem, RuntimeError};
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
|
@ -44,6 +45,12 @@ impl Output {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum StrSegment {
|
||||||
|
Interpolation(Located<Expr>),
|
||||||
|
Plaintext(InlinableString),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
// Literals
|
// Literals
|
||||||
|
@ -55,10 +62,7 @@ pub enum Expr {
|
||||||
// Int and Float store a variable to generate better error messages
|
// Int and Float store a variable to generate better error messages
|
||||||
Int(Variable, i64),
|
Int(Variable, i64),
|
||||||
Float(Variable, f64),
|
Float(Variable, f64),
|
||||||
Str {
|
Str(Vec<StrSegment>),
|
||||||
interpolations: Vec<(Box<str>, Symbol)>,
|
|
||||||
suffix: Box<str>,
|
|
||||||
},
|
|
||||||
List {
|
List {
|
||||||
list_var: Variable, // required for uniqueness of the list
|
list_var: Variable, // required for uniqueness of the list
|
||||||
elem_var: Variable,
|
elem_var: Variable,
|
||||||
|
@ -249,7 +253,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::Expr::Str(literal) => flatten_str_literal(env, scope, literal),
|
ast::Expr::Str(literal) => flatten_str_literal(env, var_store, scope, literal),
|
||||||
ast::Expr::List(loc_elems) => {
|
ast::Expr::List(loc_elems) => {
|
||||||
if loc_elems.is_empty() {
|
if loc_elems.is_empty() {
|
||||||
(
|
(
|
||||||
|
@ -1320,32 +1324,39 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flatten_str_literal(
|
fn flatten_str_literal<'a>(
|
||||||
env: &mut Env<'_>,
|
env: &mut Env<'a>,
|
||||||
|
var_store: &mut VarStore,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
literal: &StrLiteral<'_>,
|
literal: &StrLiteral<'a>,
|
||||||
) -> (Expr, Output) {
|
) -> (Expr, Output) {
|
||||||
use ast::StrLiteral::*;
|
use ast::StrLiteral::*;
|
||||||
|
|
||||||
match literal {
|
match literal {
|
||||||
PlainLine(str_slice) => (
|
PlainLine(str_slice) => (
|
||||||
Expr::Str {
|
Expr::Str(vec![StrSegment::Plaintext((*str_slice).into())]),
|
||||||
interpolations: Vec::new(),
|
|
||||||
suffix: (*str_slice).into(),
|
|
||||||
},
|
|
||||||
Output::default(),
|
Output::default(),
|
||||||
),
|
),
|
||||||
LineWithEscapes(segments) => flatten_str_lines(env, scope, &[segments]),
|
Line(segments) => flatten_str_lines(env, var_store, scope, &[segments]),
|
||||||
Block(lines) => flatten_str_lines(env, scope, lines),
|
Block(lines) => flatten_str_lines(env, var_store, scope, lines),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flatten_str_lines(
|
fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
||||||
env: &mut Env<'_>,
|
match expr {
|
||||||
|
ast::Expr::Var { .. } => true,
|
||||||
|
ast::Expr::Access(sub_expr, _) => is_valid_interpolation(sub_expr),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flatten_str_lines<'a>(
|
||||||
|
env: &mut Env<'a>,
|
||||||
|
var_store: &mut VarStore,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
lines: &[&[StrSegment<'_>]],
|
lines: &[&[ast::StrSegment<'a>]],
|
||||||
) -> (Expr, Output) {
|
) -> (Expr, Output) {
|
||||||
use StrSegment::*;
|
use ast::StrSegment::*;
|
||||||
|
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
let mut interpolations = Vec::new();
|
let mut interpolations = Vec::new();
|
||||||
|
@ -1360,37 +1371,32 @@ fn flatten_str_lines(
|
||||||
Unicode(loc_digits) => {
|
Unicode(loc_digits) => {
|
||||||
todo!("parse unicode digits {:?}", loc_digits);
|
todo!("parse unicode digits {:?}", loc_digits);
|
||||||
}
|
}
|
||||||
Interpolated {
|
Interpolated(loc_expr) => {
|
||||||
module_name,
|
if is_valid_interpolation(loc_expr.value) {
|
||||||
ident,
|
let (loc_expr, new_output) = canonicalize_expr(
|
||||||
region,
|
env,
|
||||||
} => {
|
var_store,
|
||||||
let (expr, new_output) =
|
scope,
|
||||||
canonicalize_lookup(env, scope, module_name, ident, region.clone());
|
loc_expr.region,
|
||||||
|
loc_expr.value,
|
||||||
|
);
|
||||||
|
|
||||||
output.union(new_output);
|
output.union(new_output);
|
||||||
|
|
||||||
match expr {
|
interpolations.push(StrSegment::Interpolation(loc_expr));
|
||||||
Expr::Var(symbol) => {
|
} else {
|
||||||
interpolations.push((buf.into(), symbol));
|
env.problem(Problem::InvalidInterpolation(loc_expr.region));
|
||||||
}
|
|
||||||
_ => {
|
return (
|
||||||
todo!("TODO gracefully handle non-ident in string interpolation.");
|
Expr::RuntimeError(RuntimeError::InvalidInterpolation(loc_expr.region)),
|
||||||
}
|
output,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = String::new();
|
|
||||||
}
|
}
|
||||||
EscapedChar(ch) => buf.push(*ch),
|
EscapedChar(ch) => buf.push(*ch),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
(Expr::Str(interpolations), output)
|
||||||
Expr::Str {
|
|
||||||
interpolations,
|
|
||||||
suffix: buf.into(),
|
|
||||||
},
|
|
||||||
output,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -471,7 +471,7 @@ fn flatten_str_literal(literal: &StrLiteral<'_>) -> Pattern {
|
||||||
|
|
||||||
match literal {
|
match literal {
|
||||||
PlainLine(str_slice) => Pattern::StrLiteral((*str_slice).into()),
|
PlainLine(str_slice) => Pattern::StrLiteral((*str_slice).into()),
|
||||||
LineWithEscapes(segments) => flatten_str_lines(&[segments]),
|
Line(segments) => flatten_str_lines(&[segments]),
|
||||||
Block(lines) => flatten_str_lines(lines),
|
Block(lines) => flatten_str_lines(lines),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -490,8 +490,8 @@ fn flatten_str_lines(lines: &[&[StrSegment<'_>]]) -> Pattern {
|
||||||
Unicode(loc_digits) => {
|
Unicode(loc_digits) => {
|
||||||
todo!("parse unicode digits {:?}", loc_digits);
|
todo!("parse unicode digits {:?}", loc_digits);
|
||||||
}
|
}
|
||||||
Interpolated { region, .. } => {
|
Interpolated(loc_expr) => {
|
||||||
return Pattern::UnsupportedPattern(region.clone());
|
return Pattern::UnsupportedPattern(loc_expr.region);
|
||||||
}
|
}
|
||||||
EscapedChar(ch) => buf.push(*ch),
|
EscapedChar(ch) => buf.push(*ch),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1236,113 +1236,6 @@ mod test_can {
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn string_with_interpolation_at_start() {
|
|
||||||
let src = indoc!(
|
|
||||||
r#"
|
|
||||||
"\(abc)defg"
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
let arena = Bump::new();
|
|
||||||
let CanExprOut {
|
|
||||||
loc_expr, problems, ..
|
|
||||||
} = can_expr_with(&arena, test_home(), src);
|
|
||||||
assert_eq!(problems, Vec::new());
|
|
||||||
// let (args, ret) = (vec![("", Located::new(0, 2, 0, 4, Var("abc")))], "defg");
|
|
||||||
// let arena = Bump::new();
|
|
||||||
// let actual = parse_with(&arena, input);
|
|
||||||
|
|
||||||
// assert_eq!(
|
|
||||||
// Ok(Expr::InterpolatedStr(&(
|
|
||||||
// arena.alloc_slice_clone(&args),
|
|
||||||
// ret
|
|
||||||
// ))),
|
|
||||||
// actual
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn string_with_interpolation_at_end() {
|
|
||||||
let src = indoc!(
|
|
||||||
r#"
|
|
||||||
"abcd\(efg)"
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
// let (args, ret) = (vec![("abcd", Located::new(0, 6, 0, 8, Var("efg")))], "");
|
|
||||||
// let arena = Bump::new();
|
|
||||||
// let actual = parse_with(&arena, input);
|
|
||||||
|
|
||||||
// assert_eq!(
|
|
||||||
// Ok(InterpolatedStr(&(arena.alloc_slice_clone(&args), ret))),
|
|
||||||
// actual
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn string_with_interpolation_in_middle() {
|
|
||||||
let src = indoc!(
|
|
||||||
r#"
|
|
||||||
"abc\(defg)hij"
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
// let (args, ret) = (vec![("abc", Located::new(0, 5, 0, 8, Var("defg")))], "hij");
|
|
||||||
// let arena = Bump::new();
|
|
||||||
// let actual = parse_with(&arena, input);
|
|
||||||
|
|
||||||
// assert_eq!(
|
|
||||||
// Ok(InterpolatedStr(&(arena.alloc_slice_clone(&args), ret))),
|
|
||||||
// actual
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn string_with_two_interpolations_in_middle() {
|
|
||||||
let src = indoc!(
|
|
||||||
r#"
|
|
||||||
"abc\(defg)hi\(jkl)mn"
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
// let (args, ret) = (
|
|
||||||
// vec![
|
|
||||||
// ("abc", Located::new(0, 5, 0, 8, Var("defg"))),
|
|
||||||
// ("hi", Located::new(0, 14, 0, 16, Var("jkl"))),
|
|
||||||
// ],
|
|
||||||
// "mn",
|
|
||||||
// );
|
|
||||||
// let arena = Bump::new();
|
|
||||||
// let actual = parse_with(&arena, input);
|
|
||||||
|
|
||||||
// assert_eq!(
|
|
||||||
// Ok(InterpolatedStr(&(arena.alloc_slice_clone(&args), ret))),
|
|
||||||
// actual
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn string_with_four_interpolations() {
|
|
||||||
let src = indoc!(
|
|
||||||
r#"
|
|
||||||
"\(abc)def\(ghi)jkl\(mno)pqrs\(tuv)"
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
// let (args, ret) = (
|
|
||||||
// vec![
|
|
||||||
// ("", Located::new(0, 2, 0, 4, Var("abc"))),
|
|
||||||
// ("def", Located::new(0, 11, 0, 13, Var("ghi"))),
|
|
||||||
// ("jkl", Located::new(0, 20, 0, 22, Var("mno"))),
|
|
||||||
// ("pqrs", Located::new(0, 30, 0, 32, Var("tuv"))),
|
|
||||||
// ],
|
|
||||||
// "",
|
|
||||||
// );
|
|
||||||
// let arena = Bump::new();
|
|
||||||
// let actual = parse_with(&arena, input);
|
|
||||||
|
|
||||||
// assert_eq!(
|
|
||||||
// Ok(InterpolatedStr(&(arena.alloc_slice_clone(&args), ret))),
|
|
||||||
// actual
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn string_with_escaped_interpolation() {
|
// fn string_with_escaped_interpolation() {
|
||||||
// assert_parses_to(
|
// assert_parses_to(
|
||||||
|
|
|
@ -199,14 +199,34 @@ pub fn constrain_expr(
|
||||||
|
|
||||||
exists(vars, And(cons))
|
exists(vars, And(cons))
|
||||||
}
|
}
|
||||||
Str { interpolations, .. } => {
|
Str(segments) => {
|
||||||
todo!(
|
use crate::builtins::str_type;
|
||||||
"constrain interpolations in a string literal {:?}",
|
use roc_can::expr::StrSegment::*;
|
||||||
interpolations
|
|
||||||
);
|
|
||||||
|
|
||||||
// use crate::builtins::{empty_list_type, float_literal, int_literal, list_type, str_type};
|
let mut cons = Vec::with_capacity(segments.len() + 1);
|
||||||
// Eq(str_type(), expected, Category::Str, region)
|
let expect_interpolated =
|
||||||
|
|region| Expected::ForReason(Reason::StrInterpolation, str_type(), region);
|
||||||
|
|
||||||
|
for segment in segments {
|
||||||
|
match segment {
|
||||||
|
Plaintext(_) => {
|
||||||
|
// Plaintext strings add no constraints
|
||||||
|
}
|
||||||
|
Interpolation(loc_expr) => {
|
||||||
|
cons.push(constrain_expr(
|
||||||
|
env,
|
||||||
|
loc_expr.region,
|
||||||
|
&loc_expr.value,
|
||||||
|
expect_interpolated(loc_expr.region),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The expression as a whole should have the type Str.
|
||||||
|
cons.push(Eq(str_type(), expected, Category::Str, region));
|
||||||
|
|
||||||
|
And(cons)
|
||||||
}
|
}
|
||||||
List {
|
List {
|
||||||
elem_var,
|
elem_var,
|
||||||
|
|
|
@ -503,8 +503,8 @@ pub fn constrain_expr(
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Str { interpolations, .. } => {
|
Str(segments) => {
|
||||||
todo!("uniq constrain interpolations {:?}", interpolations);
|
todo!("uniq constrain interpolations {:?}", segments);
|
||||||
// let uniq_type = var_store.fresh();
|
// let uniq_type = var_store.fresh();
|
||||||
// let inferred = str_type(Bool::variable(uniq_type));
|
// let inferred = str_type(Bool::variable(uniq_type));
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ pub enum Problem {
|
||||||
alias_name: Symbol,
|
alias_name: Symbol,
|
||||||
region: Region,
|
region: Region,
|
||||||
},
|
},
|
||||||
|
InvalidInterpolation(Region),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
@ -125,6 +126,8 @@ pub enum RuntimeError {
|
||||||
|
|
||||||
NonExhaustivePattern,
|
NonExhaustivePattern,
|
||||||
|
|
||||||
|
InvalidInterpolation(Region),
|
||||||
|
|
||||||
/// When the author specifies a type annotation but no implementation
|
/// When the author specifies a type annotation but no implementation
|
||||||
NoImplementation,
|
NoImplementation,
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,6 +262,12 @@ pub fn can_problem<'b>(
|
||||||
alloc.reflow(" can occur in this position."),
|
alloc.reflow(" can occur in this position."),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
|
Problem::InvalidInterpolation(region) => {
|
||||||
|
todo!(
|
||||||
|
"TODO report an invalid string interpolation at region {:?}",
|
||||||
|
region
|
||||||
|
);
|
||||||
|
}
|
||||||
Problem::RuntimeError(runtime_error) => pretty_runtime_error(alloc, runtime_error),
|
Problem::RuntimeError(runtime_error) => pretty_runtime_error(alloc, runtime_error),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -524,6 +530,12 @@ fn pretty_runtime_error<'b>(
|
||||||
alloc.region(region),
|
alloc.region(region),
|
||||||
alloc.reflow("Only variables can be updated with record update syntax."),
|
alloc.reflow("Only variables can be updated with record update syntax."),
|
||||||
]),
|
]),
|
||||||
|
RuntimeError::InvalidInterpolation(region) => {
|
||||||
|
todo!(
|
||||||
|
"TODO runtime error for an invalid string interpolation at region {:?}",
|
||||||
|
region
|
||||||
|
);
|
||||||
|
}
|
||||||
RuntimeError::NoImplementation => todo!("no implementation, unreachable"),
|
RuntimeError::NoImplementation => todo!("no implementation, unreachable"),
|
||||||
RuntimeError::NonExhaustivePattern => {
|
RuntimeError::NonExhaustivePattern => {
|
||||||
unreachable!("not currently reported (but can blow up at runtime)")
|
unreachable!("not currently reported (but can blow up at runtime)")
|
||||||
|
|
|
@ -781,7 +781,7 @@ fn to_expr_report<'b>(
|
||||||
unreachable!("I don't think these can be reached")
|
unreachable!("I don't think these can be reached")
|
||||||
}
|
}
|
||||||
|
|
||||||
Reason::InterpolatedStringVar => {
|
Reason::StrInterpolation => {
|
||||||
unimplemented!("string interpolation is not implemented yet")
|
unimplemented!("string interpolation is not implemented yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -875,6 +875,10 @@ fn add_category<'b>(
|
||||||
Int => alloc.concat(vec![this_is, alloc.text(" an integer of type:")]),
|
Int => alloc.concat(vec![this_is, alloc.text(" an integer of type:")]),
|
||||||
Float => alloc.concat(vec![this_is, alloc.text(" a float of type:")]),
|
Float => alloc.concat(vec![this_is, alloc.text(" a float of type:")]),
|
||||||
Str => alloc.concat(vec![this_is, alloc.text(" a string of type:")]),
|
Str => alloc.concat(vec![this_is, alloc.text(" a string of type:")]),
|
||||||
|
StrInterpolation => alloc.concat(vec![
|
||||||
|
this_is,
|
||||||
|
alloc.text(" a value in a string interpolation, which was of type:"),
|
||||||
|
]),
|
||||||
|
|
||||||
Lambda => alloc.concat(vec![this_is, alloc.text(" an anonymous function of type:")]),
|
Lambda => alloc.concat(vec![this_is, alloc.text(" an anonymous function of type:")]),
|
||||||
|
|
||||||
|
|
|
@ -277,21 +277,53 @@ mod solve_expr {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// // INTERPOLATED STRING
|
// INTERPOLATED STRING
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn infer_interpolated_string() {
|
fn infer_interpolated_string() {
|
||||||
// infer_eq(
|
infer_eq(
|
||||||
// indoc!(
|
indoc!(
|
||||||
// r#"
|
r#"
|
||||||
// whatItIs = "great"
|
whatItIs = "great"
|
||||||
|
|
||||||
// "type inference is \(whatItIs)!"
|
"type inference is \(whatItIs)!"
|
||||||
// "#
|
"#
|
||||||
// ),
|
),
|
||||||
// "Str",
|
"Str",
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn infer_interpolated_var() {
|
||||||
|
infer_eq(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
whatItIs = "great"
|
||||||
|
|
||||||
|
str = "type inference is \(whatItIs)!"
|
||||||
|
|
||||||
|
whatItIs
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
"Str",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn infer_interpolated_field() {
|
||||||
|
infer_eq(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
rec = { whatItIs: "great" }
|
||||||
|
|
||||||
|
str = "type inference is \(rec.whatItIs)!"
|
||||||
|
|
||||||
|
rec
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
"{ whatItIs : Str }",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// LIST MISMATCH
|
// LIST MISMATCH
|
||||||
|
|
||||||
|
|
|
@ -151,10 +151,9 @@ impl Variable {
|
||||||
pub const EMPTY_TAG_UNION: Variable = Variable(2);
|
pub const EMPTY_TAG_UNION: Variable = Variable(2);
|
||||||
// Builtins
|
// Builtins
|
||||||
const BOOL_ENUM: Variable = Variable(3);
|
const BOOL_ENUM: Variable = Variable(3);
|
||||||
pub const BOOL: Variable = Variable(4);
|
pub const BOOL: Variable = Variable(4); // Used in `if` conditions
|
||||||
pub const LIST_GET: Variable = Variable(5);
|
|
||||||
|
|
||||||
pub const NUM_RESERVED_VARS: usize = 6;
|
pub const NUM_RESERVED_VARS: usize = 5;
|
||||||
|
|
||||||
const FIRST_USER_SPACE_VAR: Variable = Variable(Self::NUM_RESERVED_VARS as u32);
|
const FIRST_USER_SPACE_VAR: Variable = Variable(Self::NUM_RESERVED_VARS as u32);
|
||||||
|
|
||||||
|
|
|
@ -904,7 +904,7 @@ pub enum Reason {
|
||||||
FloatLiteral,
|
FloatLiteral,
|
||||||
IntLiteral,
|
IntLiteral,
|
||||||
NumLiteral,
|
NumLiteral,
|
||||||
InterpolatedStringVar,
|
StrInterpolation,
|
||||||
WhenBranch {
|
WhenBranch {
|
||||||
index: Index,
|
index: Index,
|
||||||
},
|
},
|
||||||
|
@ -930,6 +930,7 @@ pub enum Category {
|
||||||
TagApply(TagName),
|
TagApply(TagName),
|
||||||
Lambda,
|
Lambda,
|
||||||
Uniqueness,
|
Uniqueness,
|
||||||
|
StrInterpolation,
|
||||||
|
|
||||||
// storing variables in the ast
|
// storing variables in the ast
|
||||||
Storage,
|
Storage,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue