Skip to content

Commit 156e5fb

Browse files
committed
Add identifier kind and optional type to ExprIdentifier
1 parent 0477978 commit 156e5fb

3 files changed

Lines changed: 123 additions & 77 deletions

File tree

src/ast.rs

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl Expr {
1818

1919
pub fn identifier_name(&self) -> Option<&str> {
2020
match self {
21-
Expr::Identifier(expr_identifier) => Some(expr_identifier.name()),
21+
Expr::Identifier(expr_identifier) => Some(expr_identifier.lookup_name()),
2222
_ => None,
2323
}
2424
}
@@ -51,16 +51,80 @@ impl Expr {
5151
}
5252

5353
#[derive(Debug, PartialEq)]
54-
pub struct ExprIdentifier(pub String);
54+
pub struct ExprIdentifier(pub String, pub IdentifierKind, pub Option<Type>);
5555

5656
impl ExprIdentifier {
5757
pub fn new(identifier: &str) -> Self {
58-
Self(identifier.to_string())
58+
Self(
59+
identifier.to_string(),
60+
Self::get_identifier_kind(identifier),
61+
None,
62+
)
5963
}
6064

61-
pub fn name(&self) -> &str {
65+
pub fn get_identifier_kind(identifier: &str) -> IdentifierKind {
66+
let identifier_prefix = &identifier[..1];
67+
68+
match identifier_prefix {
69+
"?" => IdentifierKind::Prompt,
70+
"!" => IdentifierKind::Secret,
71+
":" => IdentifierKind::Var,
72+
"@" => IdentifierKind::Client,
73+
_ => IdentifierKind::Builtin,
74+
}
75+
}
76+
77+
/// The full name of the identifier from the source code
78+
///
79+
/// This is different from [Self::name] as it always includes a sigil prefix
80+
/// for variables, prompts, secrets, and client identifiers.
81+
pub fn full_name(&self) -> &str {
6282
&self.0
6383
}
84+
85+
/// The look up name for the identifier
86+
///
87+
/// For builtins this is just the identifier name
88+
///
89+
/// For variables, prompts, secrets, and client identifiers, it returns the
90+
/// non sigil prefix version of the identifier.
91+
///
92+
/// - builtin_fn => builtin_fn
93+
/// - :variable => variable
94+
/// - ?prompt => prompt
95+
/// - !secret => secret
96+
/// - @client => client
97+
///
98+
pub fn lookup_name(&self) -> &str {
99+
match self.identifier_kind() {
100+
IdentifierKind::Builtin => &self.0,
101+
IdentifierKind::Var => &self.0[1..],
102+
IdentifierKind::Prompt => &self.0[1..],
103+
IdentifierKind::Secret => &self.0[1..],
104+
IdentifierKind::Client => &self.0[1..],
105+
}
106+
}
107+
108+
pub fn sigil(&self) -> &str {
109+
&self.0[..1]
110+
}
111+
112+
pub fn identifier_kind(&self) -> &IdentifierKind {
113+
&self.1
114+
}
115+
116+
pub fn get_type(&self) -> &Option<Type> {
117+
&self.2
118+
}
119+
}
120+
121+
#[derive(Debug, PartialEq)]
122+
pub enum IdentifierKind {
123+
Builtin,
124+
Var,
125+
Prompt,
126+
Secret,
127+
Client,
64128
}
65129

66130
#[derive(Debug, PartialEq)]

src/compiler.rs

Lines changed: 54 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use std::rc::Rc;
44

55
use crate::{
6-
ast::{Expr, ExprS},
6+
ast::{Expr, ExprS, IdentifierKind},
77
builtins::{BuiltinFn, BuiltinFns},
88
errors::{
99
CompileError::{self, WrongNumberOfArgs},
@@ -357,78 +357,60 @@ fn compile_expr(
357357
}
358358
}
359359
Expr::Identifier(identifier) => {
360-
let identifier_name = identifier.0.as_str();
361-
362-
if let Some((_, index)) = env.get_builtin_index(identifier_name) {
363-
codes.push(GET);
364-
codes.push(lookup::BUILTIN);
365-
codes.push(index);
366-
} else if let Some((_, index)) = env.get_user_builtin_index(identifier_name) {
367-
codes.push(GET);
368-
codes.push(lookup::USER_BUILTIN);
369-
codes.push(index);
370-
} else {
371-
let identifier_prefix = &identifier_name[..1];
372-
let identifier_suffix = &identifier_name[1..];
373-
374-
match identifier_prefix {
375-
"?" => {
376-
if let Some(index) = get(&env.prompts, identifier_suffix) {
377-
codes.push(GET);
378-
codes.push(lookup::PROMPT);
379-
codes.push(index);
380-
} else {
381-
errs.push((
382-
CompileError::Undefined(identifier_name.to_string()).into(),
383-
span.clone(),
384-
));
385-
}
386-
}
387-
"!" => {
388-
if let Some(index) = get(&env.secrets, identifier_suffix) {
389-
codes.push(GET);
390-
codes.push(lookup::SECRET);
391-
codes.push(index);
392-
} else {
393-
errs.push((
394-
CompileError::Undefined(identifier_name.to_string()).into(),
395-
span.clone(),
396-
));
397-
}
398-
}
399-
":" => {
400-
if let Some(index) = get(&env.vars, identifier_suffix) {
401-
codes.push(GET);
402-
codes.push(lookup::VAR);
403-
codes.push(index);
404-
} else {
405-
errs.push((
406-
CompileError::Undefined(identifier_name.to_string()).into(),
407-
span.clone(),
408-
));
409-
}
410-
}
411-
"@" => {
412-
if let Some(index) = get(&env.client_context, identifier_suffix) {
413-
codes.push(GET);
414-
codes.push(lookup::CLIENT_CTX);
415-
codes.push(index);
416-
} else {
417-
errs.push((
418-
CompileError::Undefined(identifier_name.to_string()).into(),
419-
span.clone(),
420-
));
421-
}
422-
}
423-
_ => {
424-
errs.push((
425-
ExprError::CompileError(CompileError::Undefined(
426-
identifier_name.to_string(),
427-
)),
428-
span.clone(),
429-
));
360+
let identifier_lookup_name = identifier.lookup_name();
361+
let identifier_name = identifier.full_name().to_string();
362+
363+
let identifier_undefined_err = (
364+
CompileError::Undefined(identifier_name).into(),
365+
span.clone(),
366+
);
367+
368+
let result = match identifier.identifier_kind() {
369+
IdentifierKind::Var => get(&env.vars, identifier_lookup_name).map(|index| {
370+
codes.push(GET);
371+
codes.push(lookup::VAR);
372+
codes.push(index);
373+
}),
374+
IdentifierKind::Prompt => get(&env.prompts, identifier_lookup_name).map(|index| {
375+
codes.push(GET);
376+
codes.push(lookup::PROMPT);
377+
codes.push(index);
378+
}),
379+
IdentifierKind::Secret => get(&env.secrets, identifier_lookup_name).map(|index| {
380+
codes.push(GET);
381+
codes.push(lookup::SECRET);
382+
codes.push(index);
383+
}),
384+
IdentifierKind::Client => {
385+
get(&env.client_context, identifier_lookup_name).map(|index| {
386+
codes.push(GET);
387+
codes.push(lookup::CLIENT_CTX);
388+
codes.push(index);
389+
})
390+
}
391+
IdentifierKind::Builtin => {
392+
if let Some((_, index)) = env.get_builtin_index(identifier_lookup_name) {
393+
codes.push(GET);
394+
codes.push(lookup::BUILTIN);
395+
codes.push(index);
396+
397+
Some(())
398+
} else if let Some((_, index)) =
399+
env.get_user_builtin_index(identifier_lookup_name)
400+
{
401+
codes.push(GET);
402+
codes.push(lookup::USER_BUILTIN);
403+
codes.push(index);
404+
405+
Some(())
406+
} else {
407+
None
430408
}
431-
};
409+
}
410+
};
411+
412+
if let None = result {
413+
errs.push(identifier_undefined_err);
432414
}
433415
}
434416
Expr::Call(expr_call) => {

src/grammar.lalrpop

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ ExprCall: ast::Expr = {
4545
// Identifier Expressions
4646

4747
ExprIdentifier: ast::Expr = <name:identifier> =>
48-
ast::Expr::Identifier(ast::ExprIdentifier(name).into());
48+
ast::Expr::Identifier(ast::ExprIdentifier::new(&name).into());
4949

5050
// Utility Types
5151

0 commit comments

Comments
 (0)