AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
Scala 3용 타입 안전 렉서·파서 라이브러리 Alpaca로, 컴파일 타임 검증과 패턴 매칭 DSL을 제공합니다
Another Lexer Parser And Compiler Alpaca. A type-safe lexer and parser library for Scala 3, featuring compile-time validation and a pattern-matching DSL.
개발 도구Scala · KotlinGitHub @halotukozak-com온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A type-safe lexer and parser library for Scala 3, featuring compile-time validation and a pattern-matching DSL.
case syntaxAdd Alpaca as a dependency in your build.mill:
//| mill-version: 1.3.1
//| mill-jvm-version: 21
import mill._
import mill.scalalib._
object myproject extends ScalaModule {
def scalaVersion = "3.9.0"
def scalacOptions = Seq("-Yretain-trees")
def mvnDeps = Seq(
mvn"com.halotukozak::alpaca::1.0.0-RC5"
)
}
Add Alpaca to your build.sbt:
libraryDependencies += "com.halotukozak" %% "alpaca" % "1.0.0-RC5"
Make sure you're using Scala 3.9.0 or later and enable the required compiler flag (Alpaca 0.3.2 and earlier also need -experimental):
scalaVersion := "3.9.0"
scalacOptions ++= Seq("-Yretain-trees")
Use Alpaca directly in your Scala CLI scripts:
//> using scala "3.9.0"
//> using dep "com.halotukozak::alpaca:1.0.0-RC5"
//> using options "-Yretain-trees"
import halotukozak.alpaca.*
// Your code here
Alpaca is also published for Scala.js 1 and Scala Native 0.5 (built with Scala.js 1.22.0 and Scala Native 0.5.12). The
same dependency works there, with %%% in sbt:
libraryDependencies += "com.halotukozak" %%% "alpaca" % "1.0.0-RC5"
In Mill, the mvn"com.halotukozak::alpaca::1.0.0-RC5" line above picks the right artifact in a ScalaJSModule or
ScalaNativeModule. In Scala CLI, add //> using platform js (or native) and write the dependency with two colons
before the version: //> using dep "com.halotukozak::alpaca::1.0.0-RC5". The -Yretain-trees flag is needed on every
platform.
Define a lexer using pattern matching with regex patterns:
import halotukozak.alpaca.*
val MyLexer = lexer:
case num @ "[0-9]+" => Token["NUM"](num.toDouble)
case "\\+" => Token["PLUS"]
case "-" => Token["MINUS"]
case "\\*" => Token["STAR"]
case "/" => Token["SLASH"]
case "\\(" => Token["LP"]
case "\\)" => Token["RP"]
case "\\s+" => Token.Ignored
Define a parser by extending the Parser class and defining grammar rules:
import halotukozak.alpaca.*
object MyParser extends Parser:
val root: Rule[Double] = rule:
case Expr(e) => e
val Expr: Rule[Double] = rule(
{ case (Expr(l), MyLexer.PLUS(_), Term(r)) => l + r },
{ case (Expr(l), MyLexer.MINUS(_), Term(r)) => l - r },
{ case Term(t) => t },
)
val Term: Rule[Double] = rule(
{ case (Term(l), MyLexer.STAR(_), Factor(r)) => l * r },
{ case (Term(l), MyLexer.SLASH(_), Factor(r)) => l / r },
{ case Factor(f) => f },
)
val Factor: Rule[Double] = rule(
{ case MyLexer.NUM(n) => n.value },
{ case (MyLexer.LP(_), Expr(e), MyLexer.RP(_)) => e },
)
import halotukozak.alpaca.*
val input = "2 + 3 * 4"
val lexemes = MyLexer.tokenize(input).getOrThrow
val result = MyParser.parse(lexemes).getOrThrow
println(result) // 14.0
The full documentation is at alpaca.halotukozak.com.
Runtime benchmarks are not run automatically in CI on push or pull requests. They can be triggered manually:
GitHub Actions — go to Actions > Runtime Benchmark > Run workflow and select the branch.
Locally — run all benchmarks (JMH + Python) from the repository root:
./mill benchmarks.runAll
Or run individual JMH suites directly:
./mill benchmarks.alpaca.runJmh
./mill benchmarks.fastparse.runJmh
Results are written to benchmarks/outputs/.
The build defines separate jvm, js, and native modules; commands below target jvm (swap in
js/native to build for those platforms):
# Compile the project
./mill jvm.compile
# Run tests
./mill jvm.test
# Generate documentation
./mill jvm.docJar
# Run test coverage
./mill jvm.scoverage.htmlReport
This project was developed as a Bachelor's Thesis. The full text is available in
the thesis.pdf file. The LaTeX source files are on
the thesis branch. The thesis is written in Polish
and does not represent the current state of the project.
Contributions are welcome. Please feel free to submit a Pull Request.
internal is part of the binary contractThe halotukozak.alpaca.internal package is not user API, but it is part of the binary contract. The lexer and parser
macros expand into code that lives in users' binaries and calls internal symbols directly:
Lexer constructor (the class every generated lexer extends), DefinedToken/IgnoredToken,
TokenInfo and Printable.apply;Production, NEL and the grammar symbols, ParseAction, the ParseTable encoding, ActionTable,
RevertedArray, the ParserExtractors actions and the Parser constructor;@publicInBinary member.A MiMa or TASTy-MiMa report on an internal class is therefore a real break for already-compiled users, not a false
positive. Don't filter it out. Changing these symbols incompatibly needs a major version.
Created by halotukozak and Corvette653
Made with ❤️ and coffee