Compare commits

...

2 Commits

Author SHA1 Message Date
01246cc0e1 Added lexing and parsing for single quote
All checks were successful
ci/woodpecker/push/workflow Pipeline was successful
2025-10-03 22:51:46 +03:00
a13dbcaa77 update README.md 2025-10-03 22:39:46 +03:00
7 changed files with 28 additions and 3 deletions

View File

@@ -63,7 +63,7 @@ Woodpecker CI/CD system is integrated.
Currently using Catch2 for unit testing.
- Lexing - complete, more token types may be added as necessary
- Parsing - This is the next step.
- Parsing - the main steps are done, but things may change as time progresses
- Optimizations -
- Emitting Bytecode - the goal.

View File

@@ -13,6 +13,7 @@ enum class TokenType {
String,
Int,
Double,
Quote,
End
};

View File

@@ -20,6 +20,7 @@ private:
std::optional<LispValue> parse_one();
LispValue parse_quote();
LispValue parse_list();
public:

View File

@@ -1,11 +1,9 @@
#pragma once
#include <concepts>
#include <deque>
#include <cstdint>
#include <string>
#include <variant>
#include <iostream>
// we're using a pure variant as our value type.
struct Integer {int64_t value;};

View File

@@ -12,6 +12,7 @@ std::ostream &operator<<(std::ostream &os, Token const &t) {
case TokenType::OpenParen: os << "OpenParen)"; break;
case TokenType::CloseParen: os << "CloseParen)"; break;
case TokenType::Dollar: os << "Dollar)"; break;
case TokenType::Quote: os << "QUOTE)"; break;
case TokenType::Symbol: os << "Symbol, " << get<string>(*t.value) << ")"; break;
case TokenType::String: os << "String, \"" << get<string>(*t.value) << "\")"; break;
case TokenType::Int: os << "Int, " << get<int64_t>(*t.value) << ")"; break;
@@ -139,6 +140,7 @@ Token Lexer::next() {
case '(': return {TokenType::OpenParen, nullopt};
case ')': return {TokenType::CloseParen, nullopt};
case '$': return {TokenType::Dollar, nullopt};
case '\'': return {TokenType::Quote, nullopt};
default:
ss.unget();
return lexNonSpecial();

View File

@@ -1,3 +1,4 @@
#include <exception>
#include <lex.hpp>
#include <parse.hpp>
@@ -13,6 +14,10 @@ void Parser::feed(Lexer l) {
}
Token Parser::get_token() {
if (ts.empty()) {
cerr << "Parser::get_token: Token requested at input end." << endl;
throw exception();
}
Token t = ts.front();
ts.pop_front();
return t;
@@ -29,6 +34,22 @@ Symbol Parser::make_symbol(string s) {
return Symbol {s};
}
LispValue Parser::parse_quote() {
// in regular lisps, a quote gets expanded to a (quote) form.
// i.e. 'a is actually (QUOTE A). This prevents the symbol from being
// evaluated.
// This is the same way we'll handle quotes for now, because I can't
// think of anything else.
List l;
l.list.push_back(make_symbol("QUOTE"));
auto next = parse_one();
// this is guaranteed to work, because if we do not have enough tokens
// to constitute another value Parser::get_token will throw an exception
l.list.push_back(*next);
return l;
}
optional<LispValue> Parser::parse_one() {
Token t = get_token();
switch (t.type) {
@@ -38,6 +59,7 @@ optional<LispValue> Parser::parse_one() {
case TokenType::Symbol: return make_symbol(get<string>(*t.value));
case TokenType::OpenParen: return parse_list();
case TokenType::CloseParen: throw "whatever";
case TokenType::Quote: return parse_quote();
// I don't know what this will actually do, in theory maybe just like the OpenParen,
// but parses things in a different namespace? unimplemented for now.

View File

@@ -1,5 +1,6 @@
#include <concepts>
#include <value.hpp>
#include <iostream>
template <typename T>