Skip to main content

Parser and transpiler for the Kahmi DSL.

Project description

kahmi-dsl

This is a Python-based configuration language for the Kahmi build system that is heavily inspired by Groovy and Gradle.

Example:

buildscript {
  dependencies = ["kahmi-git", "kahmi-cxx"]
}

let cxx = load("kahmi-cxx")
let git = load("kahmi-git")

name = "myproject"
version = git.version()

cxx.build("main") {
  srcs = glob("src/*.cpp")
  type = "executable"
}

Syntax & Semantics

The Kahmi DSL is not a strict superset of the Python language, instead it wraps Python code and swaps between DSL parsing and Python code parsing.

Kahmi DSL Syntax

  1. Define a local variable with the let Keyword

    Local variables are defined using the let keyword. The variable can then be addressed in Python expressions or as call block targets (see below). The right hand side of the assignment must be a Python expression.

    let my_variable = 42
    
  2. Set a property on the current context object

    The same syntax but without the let keyword assigns the value to a member of the current context object instead of to a local variable.

    nmae = "my-project"
    version = git.version()
    
  3. Configure blocks

    A configure block basically generates a Python function, called the "closure", and passes it to the specified target. The closure that is defined after the target is passed to the target by either calling it's configure() method or calling the target directly.

    print("Hello, World!")  # Call without body
    
    buildscript {
      dependencies = ["kahmi-python"]
    }
    
    cxx.build("main") {
      srcs = glob("src/*.cpp")
    }
    

    At the root level, every Kahmi script is basically a closure that is executed against the main context object.

Python Syntax Extensions

When parsing a Python expression, Kahmi injects support for multi-line lambdas and macros.

  1. Multi-line lambdas

    The Kahmi DSL parser injects the ability to define multi-line lambdas in any Python expression. The lambda syntax is inspired by Javascript/Typescript and uses => as the lambda arrow operation to connect the argument definition with the lambda body.

    A lambda with braces requires a return statement, otherwhise the return value of the lambda will be None. Single-statement lambdas are not currently supported with this syntax (although you can always fall back to standard syntax lambda: <expr>).

    let myFunc = () => {
      import random
      return random.random()
    }
    
    print(myFunc())
    

    Nesting lambdas is supported and has the expected semantics except if used in comprehensions (as they introduce a new scope that can not be captured by the function definition that is a multi-line lambda is transpiled to).

  2. Macros

    Macros are plugins that can be enabled in the Kahmi DSL parser to implement custom parsing logic following a macro identifier. The Kahmi DSL parser comes with a YAML plugin out of the box:

    buildscript {
      dependencies = !yaml {
        - kahmi-git
        - kahmi-python
      }
    }
    
  3. Dynamic name lookup

    Names are resolved slightly different in Kahmi Python expressions. The local scope will always be resolved first. Subsequently, the current context object's members are checked, then the parent closure's local variables and context object, etc. Then finally, the global variables and builtins.

    dependencies = ["kahmi-python"]
    print(dependencies)
    print('dependencies' in locals())
    print('dependencies' in vars(self))
    

    Explanation: The property assignment sets the dependencies attribute on the current context object. Looking up the variable will first search it in the locals, but not find it there and subsequently find it in the context object (also referrable to as self).

Built-ins

Kahmi only provides two additional built-in functions on top of what is provided by Python, and they are only necessary for the execution of Kahmi's generated Python code.

Name Description
self The root context object for the script.
__lookup__(name, locals_, ctx) Helper function to resolve the targets of call blocks.

Under the hood

Kahmi comes with a simple cli that allows you to run any Kahmi script, but given the limited ability to override the root context object it is expected that it does not serve much use outside of debugging and development.

$ python -m kahmi.dsl examples/hello.kmi

Using the -E option, you can retrieve the Python code that a Kahmi file is transpiled to. This is especially useful to understand how Kahmi constructs are converted into Python. Below are some examples:

let msg = (name) => {
  return 'Hello, ' + name
}('World')

print(msg)
def lambda_stdin_1_10(name):
    return 'Hello, ' + name


msg = lambda_stdin_1_10('World')
__runtime__['print'](msg)

buildscript {
  dependencies = ["kahmi-python"]
}
@__runtime__.closure()
def __configure_buildscript(self):
    self.dependencies = ['kahmi-python']


__configure_buildscript_self_target = __runtime__['buildscript']
with __runtime__.pushing(__runtime__['locals']()):
    if __runtime__['hasattr'](__configure_buildscript_self_target, 'configure'):
        __configure_buildscript_self_target.configure(__configure_buildscript)
    else:
        __configure_buildscript_self_target(__configure_buildscript)

Copyright © 2021 Niklas Rosenstein

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kahmi-dsl-0.1.1.tar.gz (16.1 kB view details)

Uploaded Source

Built Distribution

kahmi_dsl-0.1.1-py3-none-any.whl (16.1 kB view details)

Uploaded Python 3

File details

Details for the file kahmi-dsl-0.1.1.tar.gz.

File metadata

  • Download URL: kahmi-dsl-0.1.1.tar.gz
  • Upload date:
  • Size: 16.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.25.1 setuptools/50.3.2 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.3

File hashes

Hashes for kahmi-dsl-0.1.1.tar.gz
Algorithm Hash digest
SHA256 f482531043af3063350d8273bada4527e7e33d90ee33d8759407d7c8d79995c3
MD5 a5459f1a6d617a3aeebe2c59c6c8c3f3
BLAKE2b-256 2f15b8da68c80cdc978a8ae48d64a3dcf13621b3ebcc35984be5159ad408db8a

See more details on using hashes here.

File details

Details for the file kahmi_dsl-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: kahmi_dsl-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 16.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.25.1 setuptools/50.3.2 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.7.3

File hashes

Hashes for kahmi_dsl-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 47e0476ed7694b3ae71c7cdcef6ccc50bb879628657f8feb93bf1e2bc42ca575
MD5 7529282c4ce046e194121be934dadaa2
BLAKE2b-256 0cab62d551de0e9bbb2cb998f7cecf54b6b284a36801b1b575cb19f5ab686d0f

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page