Skip to content

Commit 3acd1af

Browse files
committed
Added support for generic character literals
1 parent 35da9bb commit 3acd1af

File tree

8 files changed

+65
-2
lines changed

8 files changed

+65
-2
lines changed

Diff for: src/ast/expr/kind.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub enum ExprKind {
1212
Boolean(bool),
1313
Integer(Integer),
1414
Float(f64),
15+
Char(String),
1516
String(String),
1617
NullTerminatedString(CString),
1718
CharLiteral(u8),

Diff for: src/lexer/mod.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,16 @@ impl<T: Text + Send> Lexer<T> {
301301
});
302302
Waiting
303303
}
304+
'\'' => {
305+
// Rune Literal
306+
self.state = State::String(StringState {
307+
value: String::new(),
308+
closing_char: '\'',
309+
modifier: StringModifier::RuneLiteral,
310+
start_source: source,
311+
});
312+
Waiting
313+
}
304314
_ if c.is_alphabetic() || c == '_' => {
305315
self.state = State::Identifier(IdentifierState {
306316
identifier: String::from(c),
@@ -370,7 +380,9 @@ impl<T: Text + Send> Lexer<T> {
370380
StringModifier::Normal | StringModifier::NullTerminated => {
371381
"Unclosed string literal"
372382
}
373-
StringModifier::CharLiteral => "Unclosed character literal",
383+
StringModifier::RuneLiteral | StringModifier::CharLiteral => {
384+
"Unclosed character literal"
385+
}
374386
};
375387

376388
return Has(TokenKind::Error(message.into()).at(state.start_source));

Diff for: src/parser/parse_expr/primary/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ impl<'a, I: Inflow<Token>> Parser<'a, I> {
8282
source,
8383
))
8484
}
85+
TokenKind::String(StringLiteral {
86+
modifier: StringModifier::RuneLiteral,
87+
..
88+
}) => {
89+
let content = self.input.advance().kind.unwrap_string().value;
90+
Ok(Expr::new(ExprKind::Char(content), source))
91+
}
8592
TokenKind::OpenParen => {
8693
self.input.advance().kind.unwrap_open_paren();
8794
let inner = self.parse_expr()?;

Diff for: src/resolve/error.rs

+7
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ pub enum ResolveErrorKind {
163163
AmbiguousSymbol {
164164
name: String,
165165
},
166+
UndeterminedCharacterLiteral,
166167
Other {
167168
message: String,
168169
},
@@ -418,6 +419,12 @@ impl Display for ResolveErrorKind {
418419
ResolveErrorKind::AmbiguousSymbol { name } => {
419420
write!(f, "Ambiguous symbol '{name}'")?;
420421
}
422+
ResolveErrorKind::UndeterminedCharacterLiteral => {
423+
write!(
424+
f,
425+
"Undetermined character literal, consider using c'A' if you want a 'char'"
426+
)?;
427+
}
421428
ResolveErrorKind::Other { message } => {
422429
write!(f, "{}", message)?;
423430
}

Diff for: src/resolve/expr/mod.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ impl<'a> PreferredType<'a> {
129129
}
130130

131131
pub fn resolve_expr(
132-
ctx: &mut ResolveExprCtx<'_, '_>,
132+
ctx: &mut ResolveExprCtx,
133133
ast_expr: &ast::Expr,
134134
preferred_type: Option<PreferredType>,
135135
initialized: Initialized,
@@ -140,6 +140,28 @@ pub fn resolve_expr(
140140
ast::ExprKind::Variable(name) => {
141141
resolve_variable_expr(ctx, name, preferred_type, initialized, source)
142142
}
143+
ast::ExprKind::Char(content) => {
144+
if content.len() == 1 {
145+
if let Some(preferred_type) = preferred_type {
146+
if let TypeKind::CInteger(CInteger::Char, _) =
147+
preferred_type.view(ctx.resolved_ast).kind
148+
{
149+
let expr = resolved::ExprKind::IntegerKnown(Box::new(IntegerKnown {
150+
rigidity: ast::IntegerRigidity::Loose(CInteger::Char, None),
151+
value: content.as_bytes()[0].into(),
152+
}))
153+
.at(source);
154+
155+
return Ok(TypedExpr::new(
156+
resolved::TypeKind::CInteger(CInteger::Char, None).at(source),
157+
expr,
158+
));
159+
}
160+
}
161+
}
162+
163+
Err(ResolveErrorKind::UndeterminedCharacterLiteral.at(source))
164+
}
143165
ast::ExprKind::Integer(value) => {
144166
let (resolved_type, expr) = match value {
145167
ast::Integer::Known(known) => (

Diff for: src/token.rs

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub enum StringModifier {
3939
Normal,
4040
NullTerminated,
4141
CharLiteral,
42+
RuneLiteral,
4243
}
4344

4445
#[derive(Clone, Debug, PartialEq)]

Diff for: tests/character_literals/main.adept

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
#[foreign]
3+
func printf(format ptr<char>, ...) int
4+
5+
func main {
6+
letter char = 'A' // Generic character literal
7+
another_letter := c'B' // C `char` literal
8+
9+
printf(c"letter = %c\n", letter)
10+
printf(c"another_letter = %c\n", another_letter)
11+
}
12+

Diff for: tests/run.sh

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ compile annotation_groups
2424
compile array_access
2525
compile bitwise_operators
2626
compile c_printf
27+
compile character_literals
2728
compile comparison_operators
2829
compile defines
2930
compile enums

0 commit comments

Comments
 (0)