Karya, built on Mon Jul 24 11:39:07 PDT 2017 (patch 33511aca01257b76b88de7c7a2763b7a965c084e)

Safe HaskellNone

Derive.Parse

Contents

Description

Tracklang parsers. Many of the parsers in here should be inverses of the ShowVal.ShowVal class.

Synopsis

Documentation

parse_val :: Text -> Either Text BaseTypes.Val Source #

Parse a single Val.

parse_attrs :: String -> Either Text Attrs.Attributes Source #

Parse attributes in the form +a+b.

parse_num :: Text -> Either Text Signal.Y Source #

Parse a number or hex code, without a type suffix.

parse_call :: Text -> Maybe Text Source #

Extract only the call part of the text.

lex1 :: Text -> (Text, Text) Source #

Lex out a single expression. This isn't really a traditional lex, because it will extract a whole parenthesized expression instead of a token.

lex :: Text -> [Text] Source #

Like lex1, but get all of them.

split_pipeline :: Text -> [[Text]] Source #

Take an expression and lex it into words, where each sublist corresponds to one expression in the pipeline.

unparsed_call :: Expr.Symbol Source #

This is a magic call name that surpresses normal parsing. Instead, the rest of the event expression is passed as a string. The only characters that can't be used are ) and |, so an unparsed call can still be included in a sub expression.

parsers

p_pcontrol :: A.Parser ScoreTypes.PControl Source #

Unlike p_control_ref, this doesn't parse a comma and a default value, because pitches don't have literals. Instead, use the pitch-control val call.

p_identifier :: Bool -> String -> A.Parser Text Source #

Identifiers are somewhat more strict than usual. They must be lowercase, and the only non-letter allowed is hyphen. This means words must be separated with hyphens, and leaves me free to give special meanings to underscores or caps if I want.

until gives additional chars that stop parsing, for idents that are embedded in another lexeme.

p_symbol Source #

Arguments

:: Bool

A call at the top level can allow a ).

-> A.Parser Expr.Symbol 

Any word in call position is considered a Str. This means that you can have calls like 4 and >, which are useful names for notes or ornaments.

expand macros

expand_macros :: (Text -> Text) -> Text -> Either Text Text Source #

Map the identifiers after a "@" through the given function. Used to implement ID macros for the REPL.

A macro looks like either @valid-id-chars or @"any chars".

ky file

data Definitions Source #

This is a mirror of Library, but with expressions instead of calls. (generators, transformers)

type Definition = (FilePath, (Expr.Symbol, Expr)) Source #

(defining_file, (Symbol, Expr))

load_ky Source #

Arguments

:: [FilePath] 
-> Text 
-> IO (Either Text (Definitions, [(FilePath, Text)]))

(all_definitions, [(import_filename, content)])

Parse ky text and load and parse all the files it imports. parse_ky describes the format of the ky file.

find_ky :: [FilePath] -> FilePath -> IO (Either Text (FilePath, Text)) Source #

Find the file in the given paths and return its filename and contents.

parse_ky :: FilePath -> Text -> Either Text ([FilePath], Definitions) Source #

Parse a ky file. This file gives a way to define new calls in the tracklang language, which is less powerful but more concise than haskell.

The syntax is a sequence of import 'path\/to\/file' lines followed by a sequence of sections. A section is a header: line followed by definitions. The header determines the type of the calls defined after it, e.g.:

import 'somelib.ky'

note generator:
x = y

alias:
>new-inst = >source-inst

Valid headers are val:, (note|control|pitch) (generator|transformer):, or alias:. A line is continued if it is indented, and -- comments until the end of the line.

This is similar to the Derive.Call.Equal call, but not quite the same:

  • It uses headers for the call type instead of equal's weird sigils.
  • The syntax is different because the arguments to equal are evaluated in place, while a file is all quoted by nature. E.g. a definition x = a b c is equivalent to an equal ^x = "(a b c). x = a (no arguments) is equivalent to ^x = a, in that x can take the same arguments as a.
  • Calls are defined as Derive.Call.Macros, which means they can include $variables, which become arguments to the call.

types

newtype Expr Source #

These are parallel to the Expr.Expr types, except they add VarTerm. The duplication is unfortunate, but as long as this remains a simple AST it seems better than the various heavyweight techniques for parameterizing an AST.

Constructors

Expr (NonEmpty.NonEmpty Call) 

Instances

data Call Source #

Constructors

Call !Expr.Symbol ![Term] 

Instances

data Term Source #

Instances

newtype Var Source #

A variable to be substituted via the Derive.Call.Macro mechanism.

Constructors

Var Text 

Instances

parse_val :: Text -> Either Text BaseTypes.Val Source #

Parse a single Val.

parse_attrs :: String -> Either Text Attrs.Attributes Source #

Parse attributes in the form +a+b.

parse_num :: Text -> Either Text Signal.Y Source #

Parse a number or hex code, without a type suffix.

parse_call :: Text -> Maybe Text Source #

Extract only the call part of the text.

lex

lex1 :: Text -> (Text, Text) Source #

Lex out a single expression. This isn't really a traditional lex, because it will extract a whole parenthesized expression instead of a token.

lex :: Text -> [Text] Source #

Like lex1, but get all of them.

split_pipeline :: Text -> [[Text]] Source #

Take an expression and lex it into words, where each sublist corresponds to one expression in the pipeline.

p_lex1 :: A.Parser () Source #

Attoparsec doesn't keep track of byte position, and always backtracks. I think this means I can't reuse p_term.

expand macros

expand_macros :: (Text -> Text) -> Text -> Either Text Text Source #

Map the identifiers after a "@" through the given function. Used to implement ID macros for the REPL.

A macro looks like either @valid-id-chars or @"any chars".

toplevel parsers

p_toplevel_call :: Bool -> A.Parser BaseTypes.Call Source #

A toplevel call has a few special syntactic forms, other than the plain call arg arg ... form parsed by p_call.

unparsed_call :: Expr.Symbol Source #

This is a magic call name that surpresses normal parsing. Instead, the rest of the event expression is passed as a string. The only characters that can't be used are ) and |, so an unparsed call can still be included in a sub expression.

p_symbol Source #

Arguments

:: Bool

A call at the top level can allow a ).

-> A.Parser Expr.Symbol 

Any word in call position is considered a Str. This means that you can have calls like 4 and >, which are useful names for notes or ornaments.

p_hex :: A.Parser Signal.Y Source #

Parse numbers of the form `0x`00 or 0x00, with an optional - prefix for negation.

p_str :: A.Parser Expr.Str Source #

A string is anything between single quotes. A single quote itself is represented by two single quotes in a row.

p_pcontrol :: A.Parser ScoreTypes.PControl Source #

Unlike p_control_ref, this doesn't parse a comma and a default value, because pitches don't have literals. Instead, use the pitch-control val call.

p_unquoted_str :: A.Parser Expr.Str Source #

Symbols can have anything in them but they have to start with a letter. This means special literals can start with wacky characters and not be ambiguous.

This should be a superset of what p_identifier will accept, so if IDs use p_identifier and Id.valid_symbol, they will also be parseable without quotes.

p_identifier :: Bool -> String -> A.Parser Text Source #

Identifiers are somewhat more strict than usual. They must be lowercase, and the only non-letter allowed is hyphen. This means words must be separated with hyphens, and leaves me free to give special meanings to underscores or caps if I want.

until gives additional chars that stop parsing, for idents that are embedded in another lexeme.

is_toplevel_word_char :: Char -> Bool Source #

A word is as permissive as possible, and is terminated by whitespace. That's because this determines how calls are allowed to be named, and for expressiveness it's nice to use symbols. For example, the slur call is just (.

At the toplevel, any character is allowed except =, which lets me write p_equal expressions without spaces. In sub calls, ) is not allowed, because then I couldn't tell where the sub call expression ends, e.g. ()). However, (() is fine, even though it looks weird.

I could get rid of the toplevel distinction by not allowing ) in calls even at the toplevel, but I have ly-( and ly-) calls and I kind of like how those look. I guess it's a crummy justification, but no need to change it unless toplevel gives more more trouble.

spaces :: A.Parser () Source #

Skip spaces, including a newline as long as the next line, skipping empty lines, is indented.

definition file

load_ky Source #

Arguments

:: [FilePath] 
-> Text 
-> IO (Either Text (Definitions, [(FilePath, Text)]))

(all_definitions, [(import_filename, content)])

Parse ky text and load and parse all the files it imports. parse_ky describes the format of the ky file.

find_ky :: [FilePath] -> FilePath -> IO (Either Text (FilePath, Text)) Source #

Find the file in the given paths and return its filename and contents.

catch_io :: Text -> IO (Either Text a) -> IO (Either Text a) Source #

Catch any IO exceptions and put them in Left.

data Definitions Source #

This is a mirror of Library, but with expressions instead of calls. (generators, transformers)

type Definition = (FilePath, (Expr.Symbol, Expr)) Source #

(defining_file, (Symbol, Expr))

parse_ky :: FilePath -> Text -> Either Text ([FilePath], Definitions) Source #

Parse a ky file. This file gives a way to define new calls in the tracklang language, which is less powerful but more concise than haskell.

The syntax is a sequence of import 'path\/to\/file' lines followed by a sequence of sections. A section is a header: line followed by definitions. The header determines the type of the calls defined after it, e.g.:

import 'somelib.ky'

note generator:
x = y

alias:
>new-inst = >source-inst

Valid headers are val:, (note|control|pitch) (generator|transformer):, or alias:. A line is continued if it is indented, and -- comments until the end of the line.

This is similar to the Derive.Call.Equal call, but not quite the same:

  • It uses headers for the call type instead of equal's weird sigils.
  • The syntax is different because the arguments to equal are evaluated in place, while a file is all quoted by nature. E.g. a definition x = a b c is equivalent to an equal ^x = "(a b c). x = a (no arguments) is equivalent to ^x = a, in that x can take the same arguments as a.
  • Calls are defined as Derive.Call.Macros, which means they can include $variables, which become arguments to the call.

parse_alias :: (Expr.Symbol, Expr) -> Either Text (ScoreTypes.Instrument, ScoreTypes.Instrument) Source #

The alias section allows only alias = inst definitions.

types

newtype Expr Source #

These are parallel to the Expr.Expr types, except they add VarTerm. The duplication is unfortunate, but as long as this remains a simple AST it seems better than the various heavyweight techniques for parameterizing an AST.

Constructors

Expr (NonEmpty.NonEmpty Call) 

Instances

data Call Source #

Constructors

Call !Expr.Symbol ![Term] 

Instances

data Term Source #

Instances

newtype Var Source #

A variable to be substituted via the Derive.Call.Macro mechanism.

Constructors

Var Text 

Instances

parsers

p_expr_ky :: A.Parser Expr Source #

As Expr parallels Expr.Expr, these parsers parallel p_expr and so on.