Code Monkey home page Code Monkey logo

tangletycoon's Introduction

TangleTycoon

TangleTycoon is another tool for generating code files from Markdown. My motivation for it is to merge documentation with some integration tests allowing for tutorials which compile for any language. Given an input markdown on stdin, group code blocks into streams, re-ordering them based on future dependencies. A stream is a set of code blocks which get accumulated to be written to a file specified by a map from streams to paths.

< $1 $BINDIR/tangletycoon.py --force --cpp main.cpp

Here, we send this readme to tangletycoon and write the default C++ stream to main.cpp. Our force flag is required since we didn't specify paths for other streams, such as the above shell block. So, we don't error when this is missing.

You can specify code blocks using backticks in Markdown and supply the language immediately after. TangleTycoon uses the header after the language specification to handle streams and dependencies. This header looks like: $LANG name=$NAME stream=$STREAM dep=$DEP. So, for C++, you might have cpp name=main stream=tangle-tycoon.cpp dep=includes. Note that while the stream is given a file name, the file name is actually specified using flags as seen above for --cpp main.cpp which maps main.cpp to the cpp stream.

Streams

A stream is a target for a contiguous sequence of code. By default, each language goes to a stream with the name of the language. Otherwise, it can be specified with stream=$STREAM

#include <iostream>

This is added to the same file as above.

void foo() {
    std::cout << "Hello, world\n";
}

Dependencies

Code can be given names, and specified as dependencies so that, within a stream, that ordering is enforced. If a recursive dependency is specified, you'll probably get an infinite loop.

int main() {
    foo();
}

Main is referencing a function which hasn't been declared, so declare it. Since this is specified as a dependency of the main code block, it will be placed before.

void foo();

Design decisions

Why no macros?

Macros are definitely a useful way to combine blocks, but they require deeper integration with the code block and looked like they would complicate the implementation. You would also need to have a common namespace across code blocks where they are isolated for now.

  • You can handle macros which you don't want generated by having the convention that the default namespace is not used
  • Macros require the same degree of dependency handling
  • Macros require more work to identify dependencies

My proposed syntax is to use the comment character for a given language, with a default of ### to surround identifiers.

Why input on stdin?

stdin input makes it easier to manipulate the markdown files before they get into TangleTycoon. For example, supporting multiple inputs just using cat, or pre-processing prior to putting input in there..

Why separate file paths from streams?

TangleTycoon targets first class support for Bazel which wants control over output file paths.

Inline outputs

TangleTycoon does not calculate results and inline them because it focuses on not needing to understand target languages and focusing on support for compiled languages and C++ in particular. Maybe with a DSL where you specify functions and mark that they should be invoked and the output serialized to string based on the type of the result, but then you have to integrate that with each language. I'm not sure that this complexity pays for itself. Rather, the way this could be handled is using tests and asserts as seen below:

def add2(x):
    return x + 2
assert 4 == lib.add2(2);

We can be sure of the result by adding a test with an assert for the expected value. Since they're adjacent, the result is clear, but if we care about the output of lib.h, it's not polluted with our results.

import lib

Why isn't the error handling more descriptive?

Patches welcome. I probably won't add anything that increases size beyond the line guards which is currently 92 lines.

To Do

  1. Handle positional arguments. Positional arguments are in a fixed order, so track which is the next remaining one, and use that one. lang is an exception, which is always positional.

So, the header is lang stream name dep...

If we make sure that resolution of dependencies happens in file order, then the case where nothing is specified results in a file per language in order.

  1. Add documentation for integration with Bazel

Footer

BINDIR=$(dirname $2)

Alternatives considered

  • Org Babel
    • Leading literate coding environment
    • Targets org files rather than markdown which prevents integration with git hosts which only support markdown.
    • No support for sessions for C++ limiting tangling and weaving.
  • Jupyter notebooks
    • Allows interleaving text with code and can have C++ support with xeus-cling
    • Personally had challenges with cling stability
    • Changing order of evaluation is done interactively, rather than repeatably.
    • Limited ability to generate multiple files automatically.
  • driusan/lmt
    • Meets a lot of the requirements: markdown, C++.
    • I got inspiration here for using the header of the code block.
    • Macros are an interesting way of re-working the ordering and better for repeating sections of code.
    • Written in Go, but I don't have a Go compiler everywhere.
  • joakimmj/md-tangle
    • Delimiting code blocks is by tilde rather than backticks as is more standard.
  • nuweb specifically targets latex.
  • noweb
  • brokestream/tangle.py Not Markdown
  • Pweave Python specific
  • Sweave R specific
  • NanoLP

tangletycoon's People

Contributors

eyepatchparrot avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.