use std::fmt::Display;
use crate::position::Position;
#[derive(Clone, PartialEq, Eq)]
pub struct SourceString {
pub offset: usize,
pub src: String,
}
impl std::fmt::Debug for SourceString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if std::env::var("VERBOSE").is_ok() {
f.debug_struct("SourceString")
.field("offset", &self.offset)
.field("src", &self.src)
.finish()
} else {
f.write_str("SourceString")
}
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct TypeName {
pub name: String,
}
impl std::fmt::Debug for TypeName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}
impl Display for TypeName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}
impl From<&str> for TypeName {
fn from(s: &str) -> Self {
TypeName { name: s.to_owned() }
}
}
#[derive(Clone, Eq)]
pub struct TypeSymbol {
pub name: TypeName,
pub position: Position,
pub id: SyntaxId,
}
impl PartialEq for TypeSymbol {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl std::fmt::Debug for TypeSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if std::env::var("VERBOSE").is_ok() {
f.debug_struct("TypeSymbol")
.field("name", &self.name)
.field("position", &self.position)
.field("id", &self.id)
.finish()
} else {
write!(f, "TypeSymbol\"{}\"", self.name.name)
}
}
}
impl Display for TypeSymbol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TypeHint {
pub sym: TypeSymbol,
pub args: Vec<TypeHint>,
pub position: Position,
}
impl TypeHint {
pub fn as_src(&self) -> String {
if self.args.is_empty() {
format!("{}", self.sym.name)
} else {
let formatted_args = self
.args
.iter()
.map(|a| a.as_src())
.collect::<Vec<_>>()
.join(", ");
format!("{}<{}>", self.sym.name, formatted_args)
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct SymbolName(pub String);
impl Display for SymbolName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl SymbolName {
pub fn is_underscore(&self) -> bool {
self.0 == "_"
}
pub fn is_placeholder(&self) -> bool {
self.0 == "__placeholder"
}
}
impl From<&str> for SymbolName {
fn from(s: &str) -> Self {
SymbolName(s.to_owned())
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct Symbol {
pub position: Position,
pub name: SymbolName,
pub id: SyntaxId,
}
impl Symbol {
pub fn new<S: AsRef<str>>(position: Position, name: S, id: SyntaxId) -> Self {
Self {
position,
name: SymbolName(name.as_ref().to_owned()),
id,
}
}
}
impl std::fmt::Debug for Symbol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if std::env::var("VERBOSE").is_ok() {
f.debug_struct("Symbol")
.field("name", &self.name)
.field("position", &self.position)
.field("id", &self.id)
.finish()
} else {
write!(f, "Symbol\"{}\"", self.name.0)
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SymbolWithHint {
pub symbol: Symbol,
pub hint: Option<TypeHint>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOperatorKind {
Add,
Subtract,
Multiply,
Divide,
Equal,
NotEqual,
LessThan,
LessThanOrEqual,
GreaterThan,
GreaterThanOrEqual,
And,
Or,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Pattern {
pub symbol: Symbol,
pub argument: Option<Symbol>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParenthesizedExpression {
pub open_paren: Position,
pub expr: Box<Expression>,
pub close_paren: Position,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParenthesizedArguments {
pub open_paren: Position,
pub arguments: Vec<Expression>,
pub close_paren: Position,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expression_ {
Match(Box<Expression>, Vec<(Pattern, Box<Expression>)>),
If(Box<Expression>, Block, Option<Block>),
While(Box<Expression>, Block),
ForIn(Symbol, Box<Expression>, Block),
Break,
Continue,
Assign(Symbol, Box<Expression>),
Let(Symbol, Option<TypeHint>, Box<Expression>),
Return(Option<Box<Expression>>),
IntLiteral(i64),
StringLiteral(String),
ListLiteral(Vec<Expression>),
TupleLiteral(Vec<Expression>),
StructLiteral(TypeSymbol, Vec<(Symbol, Expression)>),
BinaryOperator(Box<Expression>, BinaryOperatorKind, Box<Expression>),
Variable(Symbol),
Call(Box<Expression>, ParenthesizedArguments),
MethodCall(Box<Expression>, Symbol, ParenthesizedArguments),
DotAccess(Box<Expression>, Symbol),
FunLiteral(FunInfo),
Block(Block),
Invalid,
}
impl Expression_ {
pub(crate) fn is_invalid_or_placeholder(&self) -> bool {
match self {
Expression_::Variable(sym) => sym.name.0 == "__placeholder",
Expression_::Invalid => true,
_ => false,
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, Copy)]
pub struct SyntaxId(pub usize);
impl std::fmt::Debug for SyntaxId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SyntaxId({})", self.0)
}
}
#[derive(Debug)]
pub struct SyntaxIdGenerator {
pub next_id: SyntaxId,
}
impl Default for SyntaxIdGenerator {
fn default() -> Self {
Self {
next_id: SyntaxId(0),
}
}
}
impl SyntaxIdGenerator {
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> SyntaxId {
let next_id = self.next_id;
self.next_id = SyntaxId(next_id.0 + 1);
next_id
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Expression {
pub pos: Position,
pub expr_: Expression_,
pub value_is_used: bool,
pub id: SyntaxId,
}
impl Expression {
pub fn new(position: Position, expr_: Expression_, id: SyntaxId) -> Self {
Self {
pos: position,
expr_,
value_is_used: true,
id,
}
}
pub fn invalid(id: SyntaxId) -> Self {
Self {
pos: Position::todo(),
expr_: Expression_::Invalid,
value_is_used: true,
id,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Block {
pub is_loop_body: bool,
pub open_brace: Position,
pub exprs: Vec<Expression>,
pub close_brace: Position,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ToplevelExpression(pub Expression);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunInfo {
pub src_string: SourceString,
pub doc_comment: Option<String>,
pub name: Option<Symbol>,
pub type_params: Vec<TypeSymbol>,
pub params: Vec<SymbolWithHint>,
pub return_hint: Option<TypeHint>,
pub body: Block,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TestInfo {
pub src_string: SourceString,
pub doc_comment: Option<String>,
pub name: Option<Symbol>,
pub body: Block,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VariantInfo {
pub name_sym: Symbol,
pub payload_hint: Option<TypeHint>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FieldInfo {
pub sym: Symbol,
pub hint: TypeHint,
pub doc_comment: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnumInfo {
pub src_string: SourceString,
pub doc_comment: Option<String>,
pub name_sym: TypeSymbol,
pub type_params: Vec<TypeSymbol>,
pub variants: Vec<VariantInfo>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructInfo {
pub src_string: SourceString,
pub doc_comment: Option<String>,
pub name_sym: TypeSymbol,
pub type_params: Vec<TypeSymbol>,
pub fields: Vec<FieldInfo>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BuiltinMethodKind {
ListAppend,
ListGet,
ListLen,
StringAppend,
StringLen,
StringSubstring,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MethodKind {
BuiltinMethod(BuiltinMethodKind, Option<FunInfo>),
UserDefinedMethod(FunInfo),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MethodInfo {
pub receiver_hint: TypeHint,
pub receiver_sym: Symbol,
pub name_sym: Symbol,
pub kind: MethodKind,
}
impl MethodInfo {
pub fn fun_info(&self) -> Option<&FunInfo> {
match &self.kind {
MethodKind::BuiltinMethod(_, fun_info) => fun_info.as_ref(),
MethodKind::UserDefinedMethod(fun_info) => Some(fun_info),
}
}
pub fn full_name(&self) -> String {
format!("{}::{}", self.receiver_hint.sym, self.name_sym.name)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Definition_ {
Fun(Symbol, FunInfo),
Method(MethodInfo),
Test(TestInfo),
Enum(EnumInfo),
Struct(StructInfo),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Definition(pub SourceString, pub Position, pub Definition_);
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ToplevelItem {
Def(Definition),
Expr(ToplevelExpression),
}