A universal, multi-language, multi-paradigm code analyzer highly inspired in mulang
This is the intermediate representation of any language. Allows us to analyse the semantics of the code independently of the paradigm or the language.
The Analyzer is the component that traverses the AST and runs the specified inspections.
The Interpreter is the component that evaluates provided Expression nodes and returns the resultant PrimitiveValue
We will be using Haskell as the target language in this example.
npm install yukigo yukigo-haskell-parser
or
yarn add yukigo yukigo-haskell-parser
import { Analyzer } from "yukigo";
import { YukigoHaskellParser } from "yukigo-haskell-parser";
const code = "doble num = num * 2";
const expectations = [
{
inspection: "HasBinding",
args: { name: "minimoEntre" },
expected: false,
},
{
inspection: "HasBinding",
args: { name: "doble" },
expected: true,
},
];
const parser = new YukigoHaskellParser();
const ast = parser.parse(code);
const analyzer = new ASTAnalyzer(ast);
const result = analyzer.analyse(expectations);
console.log(results);
// [
// {
// rule: {
// inspection: "HasBinding",
// args: { name: "minimoEntre" },
// expected: false,
// },
// passed: true,
// actual: false,
// },
// {
// rule: {
// inspection: "HasBinding",
// args: { name: "doble" },
// expected: true,
// },
// passed: true,
// actual: true,
// },
// ];import { Analyzer, translateMulangToInspectionRules } from "yukigo";
import { YukigoHaskellParser } from "yukigo-haskell-parser";
const code = `
squareList :: [Int] -> [Int]
squareList xs = map (\n -> n * n) xs
square :: Int -> Int
square n = n * n
squareList2 :: [Int] -> [Int]
squareList2 = map square
`;
// Assuming the expectations are in a yaml file. Implement a way to load the actual file.
const mulangInspections = `
expectations:
- !ruby/hash:ActiveSupport::HashWithIndifferentAccess
binding: squareList
inspection: HasBinding
- !ruby/hash:ActiveSupport::HashWithIndifferentAccess
binding: squareList
inspection: HasLambdaExpression
- !ruby/hash:ActiveSupport::HashWithIndifferentAccess
binding: square
inspection: HasArithmetic
- !ruby/hash:ActiveSupport::HashWithIndifferentAccess
binding: doble
inspection: Not:HasBinding
- !ruby/hash:ActiveSupport::HashWithIndifferentAccess
binding: square
inspection: Uses:n
- !ruby/hash:ActiveSupport::HashWithIndifferentAccess
binding: squareList2
inspection: Uses:map
`;
const expectations = translateMulangToInspectionRules(mulangInspections);
const parser = new YukigoHaskellParser();
const ast = parser.parse(code);
const analyzer = new Analyzer(ast);
const result = analyzer.analyse(expectations);
console.log(results);
// [
// {
// rule: { inspection: "HasBinding", args: [Object], expected: true },
// passed: true,
// actual: true,
// },
// {
// rule: {
// inspection: "HasLambdaExpression",
// args: [Object],
// expected: true,
// },
// passed: true,
// actual: true,
// },
// {
// rule: { inspection: "HasArithmetic", args: [Object], expected: true },
// passed: true,
// actual: true,
// },
// {
// rule: { inspection: "HasBinding", args: [Object], expected: false },
// passed: true,
// actual: false,
// },
// {
// rule: { inspection: "Uses", args: [Object], expected: true },
// passed: true,
// actual: true,
// },
// {
// rule: { inspection: "Uses", args: [Object], expected: true },
// passed: true,
// actual: true,
// },
// ];- yukigo-ast: A library of AST node definitions and utilities for making yukigo parsers
- CLI
- create-yukigo-parser: A scaffolding tool to quickstart a yukigo parser with recommended configuration
- Haskell
- Prolog
A yukigo's parser is a class that implements the interface YukigoParser which exposes a public method called parse and an errors array like this:
errors: string[];
parse: (code: string) => AST;The package yukigo-core has all the current supported AST nodes.
For the grammar, you can use a tool like Jison or Nearley.
Here's a tutorial for implementing a small custom language.