From eca89acee00faf6e9ef55d84780e6eeddf225e5c Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Wed, 18 Jul 2012 20:57:59 +0100 Subject: [PATCH 001/284] initial --- JQ.hs | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ Lexer.x | 101 +++++++++++++++++++++++++++++++++++ Main.hs | 22 ++++++++ Parser.y | 78 +++++++++++++++++++++++++++ 4 files changed, 358 insertions(+) create mode 100644 JQ.hs create mode 100644 Lexer.x create mode 100644 Main.hs create mode 100644 Parser.y diff --git a/JQ.hs b/JQ.hs new file mode 100644 index 00000000..ca8df794 --- /dev/null +++ b/JQ.hs @@ -0,0 +1,157 @@ +module JQ where +import Text.JSON +import Text.JSON.String +import Data.Maybe +import Data.List (sortBy,sort,groupBy) +import Data.Function (on) +import Data.Ord (comparing) +import Control.Monad +import Control.Monad.Writer +import Control.Monad.List +import Control.Monad.Reader + +type Path = [Either Int String] + +type Program = JSValue -> [(JSValue, Path)] + +type JQ = ReaderT JSValue (WriterT Path []) + +runJQ :: JQ a -> JSValue -> [a] +runJQ prog val = map fst $ runWriterT $ runReaderT prog val + +(>|) :: JQ JSValue -> JQ a -> JQ a +a >| b = do + val <- a + local (const val) b + +collect :: JQ a -> JQ [a] +collect prog = do + arg <- ask + return $ runJQ prog arg + +collectPaths :: JQ a -> JQ [(a,Path)] +collectPaths prog = do + arg <- ask + return $ runWriterT $ runReaderT prog arg + +insert :: JSValue -> (JSValue, Path) -> JSValue +insert base (replace, []) = replace +insert (JSArray values) (replace, ((Left n):rest)) = JSArray values' + where + (left, (_:right)) = splitAt n values + values' = left ++ [replace] ++ right +insert (JSObject obj) (replace, ((Right k):rest))= JSObject $ toJSObject obj' + where + withoutK = filter ((/= k) . fst) $ fromJSObject obj + obj' = (k, replace):withoutK + + +eqj a b = JSBool $ a == b + + +liftp :: (JSValue -> JSValue) -> JQ JSValue +liftp f = liftM f ask + +idp = undefined +failp t = [] + +constp :: JSValue -> Program +constp t t' = idp t + +anyj :: [JSValue] -> Bool +anyj values = any isTrue values + where + isTrue (JSBool False) = False + isTrue (JSNull) = False + isTrue _ = True + +selectp prog = do + match <- collect prog + guard $ anyj match + ask + +constStr :: String -> JQ JSValue +constStr = return . JSString . toJSString + +constInt :: Int -> JQ JSValue +constInt = return . JSRational False . toRational + +updatep p = do + t <- ask + liftM (foldl insert t) $ collectPaths p + +arrayp prog = liftM JSArray $ collect prog + + +childp' :: JSValue -> JQ JSValue +childp' (JSArray values) = msum [tell [Left i] >> return v | (v,i) <- zip values [0..]] +childp' (JSObject obj) = msum [tell [Right k] >> return v | (k,v) <- fromJSObject obj] +childp' _ = mzero + +childp = ask >>= childp' + +--findp :: Program -> Program +findp prog = do + found <- collect prog + if anyj found then ask else childp >| findp prog + +groupp prog = do + list <- ask + case list of + JSArray values -> do + marked <- forM values $ \v -> do + m <- collect (return v >| prog) + return (m,v) + msum $ + map (return . JSArray . map snd) $ + groupBy ((==) `on` fst) $ + sortBy (comparing fst) $ + marked + _ -> return JSNull + + + + +withArray f (JSArray values) = JSArray $ f values +withArray f x = x + +callp "select" [p] = selectp p +callp "find" [p] = findp p +callp "set" [p] = updatep p +callp "sort" [] = liftp (withArray sort) +callp "group" [p] = groupp p + +lookupj :: JSValue -> JSValue -> JQ JSValue +lookupj (JSArray values) (JSRational _ n) = do + let idx = round n + tell [Left idx] + if idx >= 0 && idx < length values + then return $ values !! idx + else return $ JSNull +lookupj (JSObject obj) (JSString s) = do + tell [Right (fromJSString s)] + case (lookup (fromJSString s) (fromJSObject obj)) of + Just x -> return x + Nothing -> return JSNull +lookupj _ _ = mzero + + +plusj (JSRational _ n1) (JSRational _ n2) = JSRational True (n1 + n2) +plusj (JSString s1) (JSString s2) = JSString $ toJSString (fromJSString s1 ++ fromJSString s2) +plusj (JSArray a1) (JSArray a2) = JSArray $ a1 ++ a2 + + +js :: JSON a => a -> JSValue +js = showJSON + +index s = do + v <- ask + lookupj v (js s) + + +dictp progs = do + liftM (JSObject . toJSObject) $ forM progs $ \(k,v) -> do + JSString k' <- k + v' <- v + return (fromJSString k', v') + diff --git a/Lexer.x b/Lexer.x new file mode 100644 index 00000000..700c69e6 --- /dev/null +++ b/Lexer.x @@ -0,0 +1,101 @@ +{ +module Lexer where +import Control.Monad.Error +} + +%wrapper "monadUserState" + +$digit = 0-9 +$alpha = [a-zA-Z_] +@reserved = "."|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"=="|"+" +@ident = $alpha [$alpha $digit]* +@string = \" ($printable)* \" + + +tokens :- + +<0> $white+ ; +<0> @reserved { tok TRes } +<0> @ident { tok TIdent } +<0> $digit+ { tok $ TInt . read } + + +<0> \" { enterString } + \" { leaveString } + ($printable # [\"\\]) { pushString id } + \\ [\"\\\/] { pushString (drop 1) } + \\ [nrt] { pushString (escape . drop 1) } +-- \\ 'u' [0-9a-fA-F]{4} +-- { pushString (parseUnicode . drop 2) } + +-- @string { \s -> TString $ init $ tail s} + + +{ + +escape :: String -> String +escape "r" = "\r" +escape "n" = "\n" +escape "t" = "\t" + +getState :: Alex AlexState +getState = Alex $ \s -> Right (s, s) + +getUserState :: Alex AlexUserState +getUserState = liftM alex_ust getState + +setUserState :: AlexUserState -> Alex () +setUserState s' = Alex $ \s -> Right (s{alex_ust = s'}, ()) + +alexEOF = return $ Nothing + +enterString input len = do + setUserState [] + alexSetStartCode string + skip input len + +pushString f i@(p, _, s) len = do + buf <- getUserState + setUserState (buf ++ [f $ take len s]) + skip i len + +leaveString input len = do + s <- getUserState + alexSetStartCode 0 + return $ Just $ TString $ concat s + + +tok f (p,_,s) len = return $ Just $ f (take len s) +data Token = TRes String | TString String | TIdent String | TInt Int + +instance Show Token where + show (TRes t) = "token " ++ t + show (TString t) = "string " ++ t + show (TIdent t) = "identifier " ++ t + show (TInt t) = "integer " ++ show t + + +type AlexUserState = [String] + +alexInitUserState = undefined + +wrapError (Alex scanner) = Alex $ \s -> case scanner s of + Left message -> Left (message ++ " at " ++ showpos (alex_pos s)) + where + showpos (AlexPn off line col) = "line " ++ show line ++ ", column " ++ show col + x -> x + +scanner = do + tok <- wrapError alexMonadScan + case tok of + Nothing -> do + s <- getState + case alex_scd s of + 0 -> return [] + string -> alexError "Unterminated string literal" + Just tok -> liftM (tok:) scanner + +runLexer :: String -> Either String [Token] +runLexer input = runAlex input scanner + +} \ No newline at end of file diff --git a/Main.hs b/Main.hs new file mode 100644 index 00000000..695520cb --- /dev/null +++ b/Main.hs @@ -0,0 +1,22 @@ +import Parser +import Lexer +import JQ +import Text.JSON +import Text.JSON.String +import System.Environment +import Control.Monad +import System.IO + + +parseJS :: String -> JSValue +parseJS s = case runGetJSON readJSValue s of + Left err -> error err + Right val -> val + + +main = do + [program] <- getArgs + json <- liftM parseJS $ hGetContents stdin + case runLexer program >>= runParser of + Left err -> putStrLn err + Right program -> mapM_ (putStrLn . encode) (runJQ program json) \ No newline at end of file diff --git a/Parser.y b/Parser.y new file mode 100644 index 00000000..544fe5b4 --- /dev/null +++ b/Parser.y @@ -0,0 +1,78 @@ +{ +module Parser where +import Lexer +import JQ +import Text.JSON +import Debug.Trace +import Data.List +import Control.Monad.Error +import Control.Monad.Reader +} + +%name runParser Exp +%tokentype { Token } + +%monad { Either String } +%error { \t -> fail $ "parse error: unexpected " ++ if null t then [] else (show $ head t) } + +%token + '|' { TRes "|" } + '.' { TRes "." } + '[' { TRes "[" } + ']' { TRes "]" } + '{' { TRes "{" } + '}' { TRes "}" } + '(' { TRes "(" } + ')' { TRes ")" } + ',' { TRes "," } + ':' { TRes ":" } + '==' { TRes "==" } + '+' { TRes "+" } + Ident { TIdent $$ } + String { TString $$ } + Int { TInt $$ } + +%left '|' +%left ',' +%nonassoc '==' +%left '+' + +%% + +Exp + : Exp '|' Exp { $1 >| $3 } + | Exp ',' Exp { $1 `mplus` $3 } + | Exp '==' Exp { liftM2 eqj $1 $3 } + | Exp '+' Exp { liftM2 plusj $1 $3 } + | Term { $1 } + +ExpD + : ExpD '|' ExpD { $1 >| $3 } + | ExpD '==' ExpD { liftM2 eqj $1 $3 } + | Term { $1 } + + +Term + : '.' { ask } + | Term '.' Ident { $1 >| index $3 } + | '.' Ident { index $2 } + | String { constStr $1 } + | Term '[' Exp ']' { do {t <- $1; i <- $3; lookupj t i} } + | Term '[' ']' { $1 >| childp } + | '(' Exp ')' { $2 } + | '[' Exp ']' { arrayp $2 } + | Int { constInt $1 } + | '{' MkDict '}' { dictp $2 } + | Ident '(' Exp ')' { callp $1 [$3] } + | Ident { callp $1 [] } + +MkDict + : { [] } + | MkDictPair { [$1] } + | MkDictPair ',' MkDict { $1:$3 } + +MkDictPair + : Ident ':' ExpD { (constStr $1, $3) } + | Ident { (constStr $1, index $1) } + | String ':' ExpD { (constStr $1, $3) } + | '(' Exp ')' ':' ExpD{ ($2, $5) } From 2002dc1a2f4c35478b55149bc1a731e65d9a4268 Mon Sep 17 00:00:00 2001 From: Stephen Date: Thu, 16 Aug 2012 01:00:30 +0100 Subject: [PATCH 002/284] Most of a C implementation of jq --- c/Makefile | 21 +++ c/builtin.c | 18 +++ c/builtin.h | 8 + c/bytecode.c | 35 +++++ c/bytecode.h | 33 ++++ c/compile.c | 288 ++++++++++++++++++++++++++++++++++ c/compile.h | 34 ++++ c/execute.c | 376 +++++++++++++++++++++++++++++++++++++++++++++ c/execute.h | 14 ++ c/forkable_stack.h | 94 ++++++++++++ c/lexer.l | 25 +++ c/main.c | 82 ++++++++++ c/opcode.c | 27 ++++ c/opcode.h | 36 +++++ c/opcode_list.h | 17 ++ c/parser.y | 162 +++++++++++++++++++ 16 files changed, 1270 insertions(+) create mode 100644 c/Makefile create mode 100644 c/builtin.c create mode 100644 c/builtin.h create mode 100644 c/bytecode.c create mode 100644 c/bytecode.h create mode 100644 c/compile.c create mode 100644 c/compile.h create mode 100644 c/execute.c create mode 100644 c/execute.h create mode 100644 c/forkable_stack.h create mode 100644 c/lexer.l create mode 100644 c/main.c create mode 100644 c/opcode.c create mode 100644 c/opcode.h create mode 100644 c/opcode_list.h create mode 100644 c/parser.y diff --git a/c/Makefile b/c/Makefile new file mode 100644 index 00000000..ca20397f --- /dev/null +++ b/c/Makefile @@ -0,0 +1,21 @@ +CC=gcc -Wall -std=gnu99 -ggdb + +.PHONY: all clean +all: parsertest + +clean: + make -Bnd | grep 'Must remake target' | \ + sed 's/.*`\(.*\)'\''.*/\1/' | grep -v '^all$$' | \ + xargs rm + + +lexer.yy.c: lexer.l + flex -o lexer.yy.c --header-file=lexer.yy.h lexer.l +lexer.yy.h: lexer.yy.c + +parser.tab.c: parser.y lexer.yy.h + bison -W -d parser.y +parser.tab.h: parser.tab.c + +parsertest: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c + $(CC) -o $@ $^ -ljansson diff --git a/c/builtin.c b/c/builtin.c new file mode 100644 index 00000000..eba81994 --- /dev/null +++ b/c/builtin.c @@ -0,0 +1,18 @@ +#include "builtin.h" + +#include + + +void f_false(json_t* input[], json_t* output[]) { + output[0] = json_false(); +} + +void f_true(json_t* input[], json_t* output[]) { + output[0] = json_true(); +} + +struct cfunction function_list[] = { + {f_true, "true", CALL_BUILTIN_1_1}, + {f_false, "false", CALL_BUILTIN_1_1}, +}; +struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; diff --git a/c/builtin.h b/c/builtin.h new file mode 100644 index 00000000..5b0d3702 --- /dev/null +++ b/c/builtin.h @@ -0,0 +1,8 @@ +#ifndef BUILTIN_H +#define BUILTIN_H + +#include "bytecode.h" + +extern struct symbol_table builtins; + +#endif diff --git a/c/bytecode.c b/c/bytecode.c new file mode 100644 index 00000000..477d3aa4 --- /dev/null +++ b/c/bytecode.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include "bytecode.h" +#include "opcode.h" + +void dump_disassembly(struct bytecode* bc) { + int pc = 0; + while (pc < bc->codelen) { + dump_operation(bc, bc->code + pc); + printf("\n"); + pc += opcode_length(bc->code[pc]); + } +} + +void dump_operation(struct bytecode* bc, uint16_t* codeptr) { + int pc = codeptr - bc->code; + printf("%04d ", pc); + const struct opcode_description* op = opcode_describe(bc->code[pc++]); + printf("%s", op->name); + if (op->flags & OP_HAS_IMMEDIATE) { + uint16_t imm = bc->code[pc++]; + printf(" "); + if (op->flags & OP_HAS_BRANCH) { + printf("%04d", pc + imm); + } else if (op->flags & OP_HAS_CONSTANT) { + json_dumpf(json_array_get(bc->constants, imm), + stdout, JSON_ENCODE_ANY); + } else if (op->flags & OP_HAS_VARIABLE) { + printf("v%d", imm); + } else { + printf("%d", imm); + } + } +} diff --git a/c/bytecode.h b/c/bytecode.h new file mode 100644 index 00000000..ddf1105a --- /dev/null +++ b/c/bytecode.h @@ -0,0 +1,33 @@ +#ifndef BYTECODE_H +#define BYTECODE_H +#include +#include + +#include "opcode.h" + +typedef void (*cfunction_ptr)(json_t* input[], json_t* output[]); + +struct cfunction { + cfunction_ptr fptr; + const char* name; + opcode callop; +}; + +#define MAX_CFUNCTION_ARGS 10 +struct symbol_table { + struct cfunction* cfunctions; + int ncfunctions; +}; + + +struct bytecode { + uint16_t* code; + int codelen; + int framesize; + json_t* constants; + struct symbol_table* globals; +}; + +void dump_disassembly(struct bytecode* code); +void dump_operation(struct bytecode* bc, uint16_t* op); +#endif diff --git a/c/compile.c b/c/compile.c new file mode 100644 index 00000000..cc344575 --- /dev/null +++ b/c/compile.c @@ -0,0 +1,288 @@ +#include +#include +#include "opcode.h" +#include "compile.h" + + +struct inst { + struct inst* next; + struct inst* prev; + + opcode op; + + union { + uint16_t intval; + struct inst* target; + json_t* constant; + char* symbol; + } imm; + + struct inst* var_binding; + int var_frame_idx; + + int bytecode_pos; // position just after this insn +}; + +static inst* inst_new(opcode op) { + inst* i = malloc(sizeof(inst)); + i->next = i->prev = 0; + i->op = op; + i->bytecode_pos = -1; + i->var_binding = 0; + i->var_frame_idx = 0; + return i; +} + +static void inst_free(struct inst* i) { + if (opcode_describe(i->op)->flags & + (OP_HAS_SYMBOL | OP_HAS_VARIABLE)) { + free(i->imm.symbol); + } + free(i); +} + +static block inst_block(inst* i) { + block b = {i,i}; + return b; +} + +block gen_noop() { + block b = {0,0}; + return b; +} + +block gen_op_simple(opcode op) { + assert(!(opcode_describe(op)->flags & OP_HAS_IMMEDIATE)); + return inst_block(inst_new(op)); +} + + +block gen_op_const(opcode op, json_t* constant) { + assert(opcode_describe(op)->flags & OP_HAS_CONSTANT); + inst* i = inst_new(op); + i->imm.constant = constant; + return inst_block(i); +} + +block gen_op_target(opcode op, block target) { + assert(opcode_describe(op)->flags & OP_HAS_BRANCH); + assert(target.last); + inst* i = inst_new(op); + i->imm.target = target.last; + return inst_block(i); +} + +block gen_op_targetlater(opcode op) { + assert(opcode_describe(op)->flags & OP_HAS_BRANCH); + inst* i = inst_new(op); + i->imm.target = 0; + return inst_block(i); +} +void inst_set_target(block b, block target) { + assert(b.first); + assert(b.first == b.last); + assert(opcode_describe(b.first->op)->flags & OP_HAS_BRANCH); + assert(target.last); + b.first->imm.target = target.last; +} + +block gen_op_var_unbound(opcode op, const char* name) { + assert(opcode_describe(op)->flags & OP_HAS_VARIABLE); + inst* i = inst_new(op); + i->imm.symbol = strdup(name); + return inst_block(i); +} + +block gen_op_var_bound(opcode op, block binder) { + assert(binder.first); + assert(binder.first == binder.last); + block b = gen_op_var_unbound(op, binder.first->imm.symbol); + b.first->var_binding = binder.first; + return b; +} + +block gen_op_symbol(opcode op, const char* sym) { + assert(opcode_describe(op)->flags & OP_HAS_SYMBOL); + inst* i = inst_new(op); + i->imm.symbol = strdup(sym); + return inst_block(i); +} + +static void inst_join(inst* a, inst* b) { + assert(a && b); + assert(!a->next); + assert(!b->prev); + a->next = b; + b->prev = a; +} + +void block_append(block* b, block b2) { + if (b2.first) { + if (b->last) { + inst_join(b->last, b2.first); + } else { + b->first = b2.first; + } + b->last = b2.last; + } +} + +block block_join(block a, block b) { + block c = a; + block_append(&c, b); + return c; +} + +block block_bind(block binder, block body) { + assert(binder.first); + assert(binder.first == binder.last); + assert(opcode_describe(binder.first->op)->flags & OP_HAS_VARIABLE); + assert(binder.first->imm.symbol); + assert(binder.first->var_binding == 0); + + binder.first->var_binding = binder.first; + for (inst* i = body.first; i; i = i->next) { + if (opcode_describe(i->op)->flags & OP_HAS_VARIABLE && + i->var_binding == 0 && + !strcmp(i->imm.symbol, binder.first->imm.symbol)) { + // bind this variable + i->var_binding = binder.first; + } + } + return block_join(binder, body); +} + + +block gen_subexp(block a) { + block c = gen_noop(); + block_append(&c, gen_op_simple(DUP)); + block_append(&c, a); + block_append(&c, gen_op_simple(SWAP)); + return c; +} + +block gen_both(block a, block b) { + block c = gen_noop(); + block jump = gen_op_targetlater(JUMP); + block fork = gen_op_targetlater(FORK); + block_append(&c, fork); + block_append(&c, a); + block_append(&c, jump); + inst_set_target(fork, c); + block_append(&c, b); + inst_set_target(jump, c); + return c; +} + + +block gen_collect(block expr) { + block c = gen_noop(); + block_append(&c, gen_op_simple(DUP)); + block_append(&c, gen_op_const(LOADK, json_array())); + block array_var = block_bind(gen_op_var_unbound(STOREV, "collect"), + gen_noop()); + block_append(&c, array_var); + + block tail = {0}; + block_append(&tail, gen_op_simple(DUP)); + block_append(&tail, gen_op_var_bound(LOADV, array_var)); + block_append(&tail, gen_op_simple(SWAP)); + block_append(&tail, gen_op_simple(APPEND)); + block_append(&tail, gen_op_var_bound(STOREV, array_var)); + block_append(&tail, gen_op_simple(BACKTRACK)); + + block_append(&c, gen_op_target(FORK, tail)); + block_append(&c, expr); + block_append(&c, tail); + + block_append(&c, gen_op_var_bound(LOADV, array_var)); + + return c; +} + +block gen_else(block a, block b) { + assert(0); +} + + +struct bytecode* block_compile(struct symbol_table* syms, block b) { + inst* curr = b.first; + int pos = 0; + int var_frame_idx = 0; + for (; curr; curr = curr->next) { + if (!curr->next) assert(curr == b.last); + pos += opcode_length(curr->op); + curr->bytecode_pos = pos; + if (opcode_describe(curr->op)->flags & OP_HAS_VARIABLE) { + assert(curr->var_binding && "unbound variable"); + if (curr->var_binding == curr) { + curr->var_frame_idx = var_frame_idx++; + } + } + } + struct bytecode* bc = malloc(sizeof(struct bytecode)); + bc->codelen = pos; + uint16_t* code = malloc(sizeof(uint16_t) * bc->codelen); + bc->code = code; + int* stack_height = malloc(sizeof(int) * (bc->codelen + 1)); + for (int i = 0; icodelen + 1; i++) stack_height[i] = -1; + pos = 0; + json_t* constant_pool = json_array(); + int maxvar = -1; + int curr_stack_height = 1; + for (curr = b.first; curr; curr = curr->next) { + const struct opcode_description* op = opcode_describe(curr->op); + if (curr_stack_height < op->stack_in) { + printf("Stack underflow at %04d\n", curr->bytecode_pos); + } + if (stack_height[curr->bytecode_pos] != -1 && + stack_height[curr->bytecode_pos] != curr_stack_height) { + // FIXME: not sure this is right at all :( + printf("Inconsistent stack heights at %04d %s\n", curr->bytecode_pos, op->name); + } + curr_stack_height -= op->stack_in; + curr_stack_height += op->stack_out; + code[pos++] = curr->op; + int opflags = op->flags; + if (opflags & OP_HAS_CONSTANT) { + code[pos++] = json_array_size(constant_pool); + json_array_append(constant_pool, curr->imm.constant); + } else if (opflags & OP_HAS_VARIABLE) { + uint16_t var = (uint16_t)curr->var_binding->var_frame_idx; + code[pos++] = var; + if (var > maxvar) maxvar = var; + } else if (opflags & OP_HAS_BRANCH) { + assert(curr->imm.target->bytecode_pos != -1); + assert(curr->imm.target->bytecode_pos > pos); // only forward branches + code[pos] = curr->imm.target->bytecode_pos - (pos + 1); + stack_height[curr->imm.target->bytecode_pos] = curr_stack_height; + pos++; + } else if (opflags & OP_HAS_CFUNC) { + assert(curr->imm.symbol); + int found = 0; + for (int i=0; incfunctions; i++) { + if (!strcmp(curr->imm.symbol, syms->cfunctions[i].name)) { + code[pos++] = i; + found = 1; + break; + } + } + assert(found); + } else if (opflags & OP_HAS_IMMEDIATE) { + code[pos++] = curr->imm.intval; + } + } + free(stack_height); + bc->constants = constant_pool; + bc->framesize = maxvar + 2; // FIXME: frames of size zero? + bc->globals = syms; + return bc; +} + +void block_free(block b) { + struct inst* next; + for (struct inst* curr = b.first; curr; curr = next) { + next = curr->next; + inst_free(curr); + } +} diff --git a/c/compile.h b/c/compile.h new file mode 100644 index 00000000..0ba54f15 --- /dev/null +++ b/c/compile.h @@ -0,0 +1,34 @@ +#include +#include "bytecode.h" +#include "opcode.h" + +struct inst; +typedef struct inst inst; + + +typedef struct block { + inst* first; + inst* last; +} block; + +block gen_noop(); +block gen_op_simple(opcode op); +block gen_op_const(opcode op, json_t* constant); +block gen_op_target(opcode op, block target); +block gen_op_var_unbound(opcode op, const char* name); +block gen_op_var_bound(opcode op, block binder); +block gen_op_symbol(opcode op, const char* name); + +block gen_subexp(block a); +block gen_both(block a, block b); +block gen_collect(block expr); +block gen_else(block a, block b); + + +void block_append(block* b, block b2); +block block_join(block a, block b); +block block_bind(block binder, block body); + +struct bytecode* block_compile(struct symbol_table*, block); + +void block_free(block); diff --git a/c/execute.c b/c/execute.c new file mode 100644 index 00000000..c06ed124 --- /dev/null +++ b/c/execute.c @@ -0,0 +1,376 @@ +#include +#include +#include +#include +#include + + +#include "opcode.h" +#include "bytecode.h" +#include "compile.h" + +#include "forkable_stack.h" + + +typedef struct { + json_t* value; + int pathidx; +} stackval; + + +json_t** pathbuf; +int pathsize; // number of allocated elements + + +int path_push(stackval sv, json_t* val) { + int pos = sv.pathidx; + assert(pos <= pathsize); + assert(pos >= 0); + if (pos == pathsize) { + pathsize = pathsize ? pathsize * 2 : 100; + pathbuf = realloc(pathbuf, sizeof(pathbuf[0]) * pathsize); + } + pathbuf[pos] = val; + return pos + 1; +} + +stackval stackval_replace(stackval value, json_t* newjs) { + stackval s = {newjs, value.pathidx}; + return s; +} + + +// Probably all uses of this function are bugs +stackval stackval_root(json_t* v) { + stackval s = {v, 0}; + return s; +} + +struct forkable_stack data_stk; +typedef struct { + FORKABLE_STACK_HEADER; + stackval sv; +} data_stk_elem; + +data_stk_elem* stk_push_frame(int n) { + return forkable_stack_push(&data_stk, sizeof(data_stk_elem) * n); +} + +void stk_pop_frame(int n) { + forkable_stack_pop(&data_stk, sizeof(data_stk_elem) * n); +} + +void stk_push(stackval val) { + data_stk_elem* s = stk_push_frame(1); + s->sv = val; +} + +stackval stk_pop() { + data_stk_elem* s = forkable_stack_peek(&data_stk, sizeof(data_stk_elem)); + stackval sv = s->sv; + forkable_stack_pop(&data_stk, sizeof(data_stk_elem)); + return sv; +} + + +typedef struct { + FORKABLE_STACK_HEADER; + struct bytecode* bc; + data_stk_elem* fp; + uint16_t* pc; +} call_stk_elem; +struct forkable_stack call_stk; + + +struct forkpoint { + FORKABLE_STACK_HEADER; + struct forkable_stack_state saved_data_stack; + struct forkable_stack_state saved_call_stack; +}; + +struct forkable_stack fork_stk; + +void stack_save(){ + struct forkpoint* fork = forkable_stack_push(&fork_stk, sizeof(struct forkpoint)); + forkable_stack_save(&data_stk, &fork->saved_data_stack); + forkable_stack_save(&call_stk, &fork->saved_call_stack); +} + +void stack_switch() { + struct forkpoint* fork = forkable_stack_peek(&fork_stk, sizeof(struct forkpoint)); + forkable_stack_switch(&data_stk, &fork->saved_data_stack); + forkable_stack_switch(&call_stk, &fork->saved_call_stack); +} + +void stack_restore(){ + struct forkpoint* fork = forkable_stack_peek(&fork_stk, sizeof(struct forkpoint)); + forkable_stack_restore(&data_stk, &fork->saved_data_stack); + forkable_stack_restore(&call_stk, &fork->saved_call_stack); + forkable_stack_pop(&fork_stk, sizeof(struct forkpoint)); +} + +#define stack_push stk_push +#define stack_pop stk_pop + +#define ON_BACKTRACK(op) ((op)+NUM_OPCODES) + +json_t* jq_next() { + assert(!forkable_stack_empty(&call_stk)); + call_stk_elem* ctx = forkable_stack_peek(&call_stk, sizeof(call_stk_elem)); + struct bytecode* bc = ctx->bc; + uint16_t* pc = ctx->pc; + data_stk_elem* fp = ctx->fp; + json_t* cpool = bc->constants; + + json_t* cfunc_input[MAX_CFUNCTION_ARGS] = {0}; + json_t* cfunc_output[MAX_CFUNCTION_ARGS] = {0}; + int backtracking = 0; + while (1) { + + dump_operation(bc, pc); + + uint16_t opcode = *pc++; + + printf("\t"); + const struct opcode_description* opdesc = opcode_describe(opcode); + data_stk_elem* param = forkable_stack_peek(&data_stk, sizeof(data_stk_elem)); + for (int i=0; istack_in; i++) { + json_dumpf(param->sv.value, stdout, JSON_ENCODE_ANY); + if (i < opdesc->stack_in-1) printf(" | "); + param = forkable_stack_peek_next(&data_stk, param, sizeof(data_stk_elem)); + } + + if (backtracking) { + printf("\t"); + opcode = ON_BACKTRACK(opcode); + backtracking = 0; + } + + printf("\n"); + + switch (opcode) { + default: assert(0 && "invalid instruction"); + + case LOADK: { + json_t* v = json_array_get(cpool, *pc++); + assert(v); + stack_push(stackval_replace(stack_pop(), v)); + break; + } + + case DUP: { + stackval v = stack_pop(); + stack_push(v); + stack_push(v); + break; + } + + case SWAP: { + stackval a = stack_pop(); + stackval b = stack_pop(); + stack_push(a); + stack_push(b); + break; + } + + case POP: { + stack_pop(); + break; + } + + case APPEND: { + // FIXME paths + json_t* v = stack_pop().value; + json_t* array = stack_pop().value; + array = json_copy(array); + json_array_append(array, v); + stack_push(stackval_root(array)); + break; + } + + case INSERT: { + stackval stktop = stack_pop(); + json_t* v = stack_pop().value; + json_t* k = stack_pop().value; + stackval objv = stack_pop(); + assert(json_is_string(k)); + assert(json_is_object(objv.value)); + json_t* obj = json_copy(objv.value); + json_object_set(obj, json_string_value(k), v); + assert(json_is_object(obj)); + stack_push(stackval_replace(objv, obj)); + stack_push(stktop); + break; + } + + case LOADV: { + uint16_t v = *pc++; + stack_push(stackval_replace(stack_pop(), fp[v].sv.value)); + break; + } + + case STOREV: { + uint16_t v = *pc++; + stackval val = stack_pop(); + printf("V%d = ", v); + json_dumpf(val.value, stdout, JSON_ENCODE_ANY); + printf("\n"); + fp[v].sv.value = val.value; + break; + } + +#if 0 + case DISPLAY: { + stackval sv = stack_pop(); + if (sv.value) { + json_dumpf(sv.value, stdout, JSON_ENCODE_ANY); + } else { + printf("#ERROR"); + } + printf(" - "); + for (int i = 0; i < sv.pathidx; i++) { + printf("/"); + json_dumpf(pathbuf[i], stdout, JSON_ENCODE_ANY); + } + printf("\n"); + return; + } +#endif + + case INDEX: { + stackval t = stack_pop(); + json_t* k = stack_pop().value; + stackval v; + if (json_is_string(k)) { + v.value = json_object_get(t.value, json_string_value(k)); + } else if (json_is_integer(k)) { + v.value = json_array_get(t.value, json_integer_value(k)); + } else { + assert(0 && "key neither string nor int"); + } + if (v.value) { + v.pathidx = path_push(t, k); + stack_push(v); + } else { + assert(0 && "bad lookup"); + } + break; + } + + + case JUMP: { + uint16_t offset = *pc++; + pc += offset; + break; + } + + case EACH: + stack_push(stackval_root(json_integer(0))); + // fallthrough + case ON_BACKTRACK(EACH): { + json_t* idxj = stack_pop().value; + int idx = json_integer_value(idxj); + stackval array = stack_pop(); + if (idx >= json_array_size(array.value)) { + goto do_backtrack; + } else { + stack_save(); + stack_push(array); + stack_push(stackval_root(json_integer(idx+1))); + call_stk_elem* ctx = forkable_stack_push(&call_stk, sizeof(call_stk_elem)); + ctx->bc = bc; + ctx->fp = fp; + ctx->pc = pc - 1; + stack_switch(); + + stackval sv = {json_array_get(array.value, idx), + path_push(array, json_integer(idx))}; + stack_push(sv); + } + break; + } + + do_backtrack: + case BACKTRACK: { + if (forkable_stack_empty(&fork_stk)) { + return 0; + } + stack_restore(); + call_stk_elem* ctx = forkable_stack_peek(&call_stk, sizeof(call_stk_elem)); + bc = ctx->bc; + pc = ctx->pc; + fp = ctx->fp; + cpool = bc->constants; + forkable_stack_pop(&call_stk, sizeof(call_stk_elem)); + backtracking = 1; + break; + } + + case FORK: { + stack_save(); + call_stk_elem* ctx = forkable_stack_push(&call_stk, sizeof(call_stk_elem)); + ctx->bc = bc; + ctx->fp = fp; + ctx->pc = pc - 1; + stack_switch(); + pc++; // skip offset this time + break; + } + case ON_BACKTRACK(FORK): { + uint16_t offset = *pc++; + pc += offset; + break; + } + + case YIELD: { + json_t* value = stack_pop().value; + call_stk_elem* ctx = forkable_stack_push(&call_stk, sizeof(call_stk_elem)); + ctx->bc = bc; + ctx->fp = fp; + ctx->pc = pc; + return value; + } + + case CALL_BUILTIN_1_1: { + stackval top = stack_pop(); + cfunc_input[0] = top.value; + struct cfunction* func = &bc->globals->cfunctions[*pc++]; + printf(" call %s\n", func->name); + func->fptr(cfunc_input, cfunc_output); + stack_push(stackval_replace(top, cfunc_output[0])); + break; + } + + + } + } +} + + +void jq_init(struct bytecode* bc, json_t* input) { + forkable_stack_init(&data_stk, sizeof(stackval) * 100); // FIXME: lower this number, see if it breaks + forkable_stack_init(&call_stk, 1024); // FIXME: lower this number, see if it breaks + forkable_stack_init(&fork_stk, 1024); // FIXME: lower this number, see if it breaks + + data_stk_elem* frame = stk_push_frame(bc->framesize); + + stack_push(stackval_root(input)); + call_stk_elem* ctx = forkable_stack_push(&call_stk, sizeof(call_stk_elem)); + ctx->pc = bc->code; + ctx->bc = bc; + ctx->fp = frame; +} + +void run_program(struct bytecode* bc) { + jq_init(bc, json_loadf(stdin, 0, 0)); + json_t* result; + while ((result = jq_next())) { + json_dumpf(result, stdout, JSON_ENCODE_ANY); + printf("\n"); + } + printf("end of results\n"); + + //assert(frame == stack_top_frame(bc->framesize)); + //stk_pop_frame(bc->framesize); + //assert(stackpos == 0); +} diff --git a/c/execute.h b/c/execute.h new file mode 100644 index 00000000..b978a8e4 --- /dev/null +++ b/c/execute.h @@ -0,0 +1,14 @@ +#include "opcode.h" +#define MAX_CFUNCTION_PARAM 10 +typedef struct { + json_t* value; + int pathidx; +} stackval; + +typedef void (*cfunction_ptr)(stackval* input, stackval* output); + +struct cfunction { + cfunction_ptr fptr; + const char* name; + opcode callop; +}; diff --git a/c/forkable_stack.h b/c/forkable_stack.h new file mode 100644 index 00000000..8043c426 --- /dev/null +++ b/c/forkable_stack.h @@ -0,0 +1,94 @@ +#include +#include +#include + +struct forkable_stack_header { + int next; +}; + +#define FORKABLE_STACK_HEADER struct forkable_stack_header fk_header_ + +struct forkable_stack { + char* stk; + + // stk+length is just past end of allocated area + int length; + + // stk+pos is just past top-of-stack item + int pos; + + // everything before stk+savedlimit must be preserved + int savedlimit; +}; + +static void forkable_stack_check(struct forkable_stack* s) { + assert(s->stk); + assert(s->length > 0); + assert(s->pos >= 0 && s->pos <= s->length); + assert(s->savedlimit >= 0 && s->savedlimit <= s->length); +} + +static int forkable_stack_empty(struct forkable_stack* s) { + return s->pos == 0; +} + +static void forkable_stack_init(struct forkable_stack* s, size_t sz) { + s->stk = malloc(sz); + s->length = sz; + s->pos = 0; + s->savedlimit = 0; + forkable_stack_check(s); +} + +static void* forkable_stack_push(struct forkable_stack* s, size_t size) { + forkable_stack_check(s); + int curr = s->pos > s->savedlimit ? s->pos : s->savedlimit; + if (curr + size > s->length) { + s->length = (size + s->length + 1024) * 2; + s->stk = realloc(s->stk, s->length); + } + void* ret = (void*)(s->stk + curr); + ((struct forkable_stack_header*)ret)->next = s->pos; + s->pos = curr + size; + return ret; +} + +static void* forkable_stack_peek(struct forkable_stack* s, size_t size) { + assert(!forkable_stack_empty(s)); + return (void*)(s->stk + s->pos - size); +} + +static void* forkable_stack_peek_next(struct forkable_stack* s, void* top, size_t size) { + struct forkable_stack_header* elem = top; + return (void*)(s->stk + elem->next - size); +} + +static void forkable_stack_pop(struct forkable_stack* s, size_t size) { + struct forkable_stack_header* elem = forkable_stack_peek(s, size); + s->pos = elem->next; +} + +struct forkable_stack_state { + int prevpos, prevlimit; +}; + +static void forkable_stack_save(struct forkable_stack* s, struct forkable_stack_state* state) { + state->prevpos = s->pos; + state->prevlimit = s->savedlimit; + if (s->pos > s->savedlimit) s->savedlimit = s->pos; +} + +static void forkable_stack_switch(struct forkable_stack* s, struct forkable_stack_state* state) { + int curr_pos = s->pos; + s->pos = state->prevpos; + state->prevpos = curr_pos; + + int curr_limit = s->savedlimit; + if (curr_pos > curr_limit) s->savedlimit = curr_pos; + state->prevlimit = curr_limit; +} + +static void forkable_stack_restore(struct forkable_stack* s, struct forkable_stack_state* state) { + s->pos = state->prevpos; + s->savedlimit = state->prevlimit; +} diff --git a/c/lexer.l b/c/lexer.l new file mode 100644 index 00000000..42103c40 --- /dev/null +++ b/c/lexer.l @@ -0,0 +1,25 @@ +%{ +#include "compile.h" +#include "parser.tab.h" /* Generated by bison. */ +%} + +%option noyywrap nounput noinput nodefault +%option reentrant +%option bison-bridge bison-locations + +%% + +"==" { return EQ; } +"as" { return AS; } +"."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];} + +[[:digit:]]+ { yylval->num = atoi(yytext); return NUMBER;} +[[:alnum:]]+ { yylval->str = strdup(yytext); return IDENT;} +[ \n\t]+ {} +%% +/* perhaps these should be calls... */ +/* +"true" { return TRUE; } +"false" { return FALSE; } +"null" { return NULL; } +*/ diff --git a/c/main.c b/c/main.c new file mode 100644 index 00000000..5017d9fa --- /dev/null +++ b/c/main.c @@ -0,0 +1,82 @@ +#include +#include "compile.h" +#include "parser.tab.h" +#include "builtin.h" + +block compile(const char* str); + +void jq_init(struct bytecode* bc, json_t* value); +json_t* jq_next(); + +void run_program(struct bytecode* bc); + +int skipline(const char* buf) { + int p = 0; + while (buf[p] == ' ' || buf[p] == '\t') p++; + if (buf[p] == '#' || buf[p] == '\n' || buf[p] == 0) return 1; + return 0; +} + +void run_tests() { + FILE* testdata = fopen("testdata","r"); + char buf[4096]; + int tests = 0, passed = 0; + + while (1) { + if (!fgets(buf, sizeof(buf), testdata)) break; + if (skipline(buf)) continue; + printf("Testing %s\n", buf); + int pass = 1; + block program = compile(buf); + block_append(&program, gen_op_simple(YIELD)); + block_append(&program, gen_op_simple(BACKTRACK)); + struct bytecode* bc = block_compile(&builtins, program); + block_free(program); + fgets(buf, sizeof(buf), testdata); + json_t* input = json_loads(buf, JSON_DECODE_ANY, 0); + jq_init(bc, input); + + while (fgets(buf, sizeof(buf), testdata)) { + if (skipline(buf)) break; + json_t* expected = json_loads(buf, JSON_DECODE_ANY, 0); + json_t* actual = jq_next(); + if (!actual) { + printf("Insufficient results\n"); + pass = 0; + break; + } else if (!json_equal(expected, actual)) { + printf("Expected "); + json_dumpf(expected, stdout, JSON_ENCODE_ANY); + printf(", but got "); + json_dumpf(actual, stdout, JSON_ENCODE_ANY); + printf("\n"); + pass = 0; + break; + } + } + if (pass) { + json_t* extra = jq_next(); + if (extra) { + printf("Superfluous result: "); + json_dumpf(extra, stdout, JSON_ENCODE_ANY); + printf("\n"); + pass = 0; + } + } + tests++; + passed+=pass; + } + fclose(testdata); + printf("%d of %d tests passed\n", passed,tests); +} + +int main(int argc, char* argv[]) { + if (argc == 1) { run_tests(); return 0; } + block blk = compile(argv[1]); + block_append(&blk, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK))); + struct bytecode* bc = block_compile(&builtins, blk); + block_free(blk); + dump_disassembly(bc); + printf("\n"); + run_program(bc); +} diff --git a/c/opcode.c b/c/opcode.c new file mode 100644 index 00000000..b14e0db6 --- /dev/null +++ b/c/opcode.c @@ -0,0 +1,27 @@ +#include "opcode.h" + +#define NONE 0 +#define CONSTANT (OP_HAS_IMMEDIATE | OP_HAS_CONSTANT) +#define VARIABLE (OP_HAS_IMMEDIATE | OP_HAS_VARIABLE) +#define BRANCH (OP_HAS_IMMEDIATE | OP_HAS_BRANCH) +#define CFUNC (OP_HAS_IMMEDIATE | OP_HAS_SYMBOL | OP_HAS_CFUNC) + +#define OP(name, imm, in, out) \ + {name, #name, imm, in, out}, + +static const struct opcode_description opcode_descriptions[] = { +#include "opcode_list.h" +}; + +static const struct opcode_description invalid_opcode_description = { + -1, "#INVALID", 0, 0, 0 +}; + + +const struct opcode_description* opcode_describe(opcode op) { + if ((int)op >= 0 && (int)op < NUM_OPCODES) { + return &opcode_descriptions[op]; + } else { + return &invalid_opcode_description; + } +} diff --git a/c/opcode.h b/c/opcode.h new file mode 100644 index 00000000..797e6a96 --- /dev/null +++ b/c/opcode.h @@ -0,0 +1,36 @@ +#ifndef OPCODE_H +#define OPCODE_H +typedef enum { +#define OP(name, imm, in, out) name, +#include "opcode_list.h" +#undef OP +} opcode; + +enum { + NUM_OPCODES = +#define OP(name, imm, in, out) +1 +#include "opcode_list.h" +#undef OP +}; + +enum { + OP_HAS_IMMEDIATE = 1, + OP_HAS_CONSTANT = 2, + OP_HAS_VARIABLE = 4, + OP_HAS_BRANCH = 8, + OP_HAS_SYMBOL = 16, + OP_HAS_CFUNC = 32 +}; +struct opcode_description { + opcode op; + const char* name; + int flags; + int stack_in, stack_out; +}; + +const struct opcode_description* opcode_describe(opcode op); + +static inline int opcode_length(opcode op) { + return 1 + (opcode_describe(op)->flags & OP_HAS_IMMEDIATE ? 1 : 0); +} +#endif diff --git a/c/opcode_list.h b/c/opcode_list.h new file mode 100644 index 00000000..d88381b7 --- /dev/null +++ b/c/opcode_list.h @@ -0,0 +1,17 @@ +OP(LOADK, CONSTANT, 1, 1) +OP(DUP, NONE, 1, 2) +OP(SWAP, NONE, 2, 2) +OP(POP, NONE, 1, 0) +OP(LOADV, VARIABLE, 1, 1) +OP(STOREV, VARIABLE, 1, 0) +OP(INDEX, NONE, 2, 1) +//OP(DISPLAY, NONE, 1, 0) +OP(YIELD, NONE, 1, 0) +OP(EACH, NONE, 1, 1) +OP(FORK, BRANCH, 0, 0) +OP(JUMP, BRANCH, 0, 0) +OP(BACKTRACK, NONE, 0, 0) +OP(APPEND, NONE, 2, 1) +OP(INSERT, NONE, 4, 2) + +OP(CALL_BUILTIN_1_1, CFUNC, 1, 1) diff --git a/c/parser.y b/c/parser.y new file mode 100644 index 00000000..e8721a17 --- /dev/null +++ b/c/parser.y @@ -0,0 +1,162 @@ +%{ +#include +#include +#include "compile.h" +%} + +%locations +%define api.pure +%union { + int num; + char* str; + block blk; +} + +%parse-param {block* answer} +%parse-param {yyscan_t lexer} +%lex-param {yyscan_t lexer} + + +%token IDENT +%token NUMBER + +%left '|' +%left ',' +%token EQ "==" +%token AS "as" +%nonassoc EQ +%left '+' + +%type Exp Term MkDict MkDictPair ExpD + +%{ +#include "lexer.yy.h" +void yyerror(YYLTYPE* loc, block* answer, yyscan_t lexer, const char *s){ + printf("ERROR: %s\n", s); +} + +static block gen_dictpair(block k, block v) { + block b = gen_subexp(k); + block_append(&b, gen_subexp(v)); + block_append(&b, gen_op_simple(INSERT)); + return b; +} + +static block gen_string(const char* str) { + return gen_op_const(LOADK, json_string(str)); +} + +static block gen_index(block obj, block key) { + return block_join(obj, block_join(gen_subexp(key), gen_op_simple(INDEX))); +} + +%} + +%% +program: Exp { *answer = $1; } + + +Exp: +Term "as" '$' IDENT '|' Exp { + $$ = gen_op_simple(DUP); + block_append(&$$, $1); + block_append(&$$, block_bind(gen_op_var_unbound(STOREV, $4), $6)); +} | + +Exp '|' Exp { + $$ = block_join($1, $3); +} | + +Exp ',' Exp { + $$ = gen_both($1, $3); +} | + +Term { + $$ = $1; +} + + +ExpD: +ExpD '|' ExpD { + $$ = block_join($1, $3); +} | + +Term { + $$ = $1; +} + + +Term: +'.' { + $$ = gen_noop(); +} | +Term '.' IDENT { + $$ = gen_index($1, gen_string($3)); +} | +'.' IDENT { + $$ = gen_index(gen_noop(), gen_string($2)); +} | +/* FIXME: string literals */ +Term '[' Exp ']' { + $$ = gen_index($1, $3); +} | +Term '[' ']' { + $$ = block_join($1, gen_op_simple(EACH)); +} | +NUMBER { + $$ = gen_op_const(LOADK, json_integer($1)); +} | +'(' Exp ')' { + $$ = $2; +} | +'[' Exp ']' { + $$ = gen_collect($2); +} | +'[' ']' { + $$ = gen_op_const(LOADK, json_array()); +} | +'{' MkDict '}' { + $$ = gen_subexp(gen_op_const(LOADK, json_object())); + block_append(&$$, $2); + block_append(&$$, gen_op_simple(POP)); +} | +IDENT { + $$ = gen_op_symbol(CALL_BUILTIN_1_1, $1); +} | +'$' IDENT { + $$ = gen_op_var_unbound(LOADV, $2); +} + +MkDict: +{ + $$=gen_noop(); +} +| +MkDictPair +{ $$ = $1; } +| MkDictPair ',' MkDict { $$=block_join($1, $3); } + +MkDictPair +: IDENT ':' ExpD { + $$ = gen_dictpair(gen_string($1), $3); + } +| IDENT { + $$ = gen_dictpair(gen_string($1), + gen_index(gen_noop(), gen_string($1))); + } +| '(' Exp ')' ':' ExpD { + $$ = gen_dictpair($2, $5); + } +%% + +block compile(const char* str) { + yyscan_t scanner; + YY_BUFFER_STATE buf; + block answer = gen_noop(); + yylex_init(&scanner); + buf = yy_scan_string(str, scanner); + yyparse(&answer, scanner); + yy_delete_buffer(buf, scanner); + yylex_destroy(scanner); + return answer; +} From fd738bfaced523da61875ca3e6cf80651247572c Mon Sep 17 00:00:00 2001 From: Stephen Date: Thu, 16 Aug 2012 01:16:08 +0100 Subject: [PATCH 003/284] an addition operator, of sorts --- c/builtin.c | 20 ++++++++++++++++++-- c/execute.c | 14 ++++++++++++++ c/opcode_list.h | 1 + c/parser.y | 7 +++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/c/builtin.c b/c/builtin.c index eba81994..ef37c28c 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -3,16 +3,32 @@ #include -void f_false(json_t* input[], json_t* output[]) { +static void f_false(json_t* input[], json_t* output[]) { output[0] = json_false(); } -void f_true(json_t* input[], json_t* output[]) { +static void f_true(json_t* input[], json_t* output[]) { output[0] = json_true(); } + +static void f_plus(json_t* input[], json_t* output[]) { + json_t* a = input[2]; + json_t* b = input[1]; + if (json_is_number(a) && json_is_number(b)) { + output[0] = json_real(json_number_value(a) + + json_number_value(b)); + } else if (json_is_array(a) && json_is_array(b)) { + output[0] = json_copy(a); + json_array_extend(output[0], b); + } else { + output[0] = json_string("wtf gaize"); + } +} + struct cfunction function_list[] = { {f_true, "true", CALL_BUILTIN_1_1}, {f_false, "false", CALL_BUILTIN_1_1}, + {f_plus, "_plus", CALL_BUILTIN_3_1}, }; struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; diff --git a/c/execute.c b/c/execute.c index c06ed124..44aaab3a 100644 --- a/c/execute.c +++ b/c/execute.c @@ -340,6 +340,20 @@ json_t* jq_next() { stack_push(stackval_replace(top, cfunc_output[0])); break; } + + case CALL_BUILTIN_3_1: { + stackval top = stack_pop(); + json_t* a = stack_pop().value; + json_t* b = stack_pop().value; + cfunc_input[0] = top.value; + cfunc_input[1] = a; + cfunc_input[2] = b; + struct cfunction* func = &bc->globals->cfunctions[*pc++]; + printf(" call %s\n", func->name); + func->fptr(cfunc_input, cfunc_output); + stack_push(stackval_replace(top, cfunc_output[0])); + break; + } } diff --git a/c/opcode_list.h b/c/opcode_list.h index d88381b7..2fe3f8a8 100644 --- a/c/opcode_list.h +++ b/c/opcode_list.h @@ -15,3 +15,4 @@ OP(APPEND, NONE, 2, 1) OP(INSERT, NONE, 4, 2) OP(CALL_BUILTIN_1_1, CFUNC, 1, 1) +OP(CALL_BUILTIN_3_1, CFUNC, 3, 1) diff --git a/c/parser.y b/c/parser.y index e8721a17..393f7a83 100644 --- a/c/parser.y +++ b/c/parser.y @@ -71,6 +71,13 @@ Exp ',' Exp { $$ = gen_both($1, $3); } | +Exp '+' Exp { + $$ = gen_noop(); + block_append(&$$, gen_subexp($1)); + block_append(&$$, gen_subexp($3)); + block_append(&$$, gen_op_symbol(CALL_BUILTIN_3_1, "_plus")); +} | + Term { $$ = $1; } From 15ad640202ee6de5f442bdf22d5207618210d0ec Mon Sep 17 00:00:00 2001 From: Stephen Date: Mon, 20 Aug 2012 15:53:20 +0100 Subject: [PATCH 004/284] Stacks grow down now --- c/forkable_stack.h | 50 +++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/c/forkable_stack.h b/c/forkable_stack.h index 8043c426..5b8ec8ad 100644 --- a/c/forkable_stack.h +++ b/c/forkable_stack.h @@ -1,6 +1,7 @@ #include #include #include +#include struct forkable_stack_header { int next; @@ -9,15 +10,18 @@ struct forkable_stack_header { #define FORKABLE_STACK_HEADER struct forkable_stack_header fk_header_ struct forkable_stack { + // Stack grows down from stk+length + char* stk; // stk+length is just past end of allocated area + // stk = malloc(length) int length; - // stk+pos is just past top-of-stack item + // stk+pos is header of top object, or stk+length if empty int pos; - // everything before stk+savedlimit must be preserved + // everything after-or-including stk+savedlimit must be preserved int savedlimit; }; @@ -29,66 +33,84 @@ static void forkable_stack_check(struct forkable_stack* s) { } static int forkable_stack_empty(struct forkable_stack* s) { - return s->pos == 0; + return s->pos == s->length; } static void forkable_stack_init(struct forkable_stack* s, size_t sz) { s->stk = malloc(sz); s->length = sz; - s->pos = 0; - s->savedlimit = 0; + s->pos = s->length; + s->savedlimit = s->length; forkable_stack_check(s); } static void* forkable_stack_push(struct forkable_stack* s, size_t size) { forkable_stack_check(s); - int curr = s->pos > s->savedlimit ? s->pos : s->savedlimit; - if (curr + size > s->length) { - s->length = (size + s->length + 1024) * 2; + int curr = s->pos < s->savedlimit ? s->pos : s->savedlimit; + if (curr - size < 0) { + assert(0); + int oldlen = s->length; + s->length = (size + oldlen + 1024) * 2; s->stk = realloc(s->stk, s->length); + int shift = s->length - oldlen; + memmove(s->stk + shift, s->stk, oldlen); + s->pos += shift; + s->savedlimit += shift; + curr += shift; } - void* ret = (void*)(s->stk + curr); + void* ret = (void*)(s->stk + curr - size); ((struct forkable_stack_header*)ret)->next = s->pos; - s->pos = curr + size; + s->pos = curr - size; + forkable_stack_check(s); return ret; } static void* forkable_stack_peek(struct forkable_stack* s, size_t size) { assert(!forkable_stack_empty(s)); - return (void*)(s->stk + s->pos - size); + forkable_stack_check(s); + return (void*)(s->stk + s->pos); } static void* forkable_stack_peek_next(struct forkable_stack* s, void* top, size_t size) { + forkable_stack_check(s); struct forkable_stack_header* elem = top; - return (void*)(s->stk + elem->next - size); + return (void*)(s->stk + elem->next); } static void forkable_stack_pop(struct forkable_stack* s, size_t size) { + forkable_stack_check(s); struct forkable_stack_header* elem = forkable_stack_peek(s, size); s->pos = elem->next; } + + struct forkable_stack_state { int prevpos, prevlimit; }; static void forkable_stack_save(struct forkable_stack* s, struct forkable_stack_state* state) { + forkable_stack_check(s); state->prevpos = s->pos; state->prevlimit = s->savedlimit; - if (s->pos > s->savedlimit) s->savedlimit = s->pos; + if (s->pos < s->savedlimit) s->savedlimit = s->pos; } static void forkable_stack_switch(struct forkable_stack* s, struct forkable_stack_state* state) { + forkable_stack_check(s); int curr_pos = s->pos; s->pos = state->prevpos; state->prevpos = curr_pos; int curr_limit = s->savedlimit; - if (curr_pos > curr_limit) s->savedlimit = curr_pos; + if (curr_pos < curr_limit) s->savedlimit = curr_pos; state->prevlimit = curr_limit; + forkable_stack_check(s); } static void forkable_stack_restore(struct forkable_stack* s, struct forkable_stack_state* state) { + forkable_stack_check(s); s->pos = state->prevpos; s->savedlimit = state->prevlimit; + forkable_stack_check(s); } From dd0d340ebafbafe92f43bbb77a96ea8531ac1307 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 21 Aug 2012 12:35:36 +0100 Subject: [PATCH 005/284] frame layout refactor --- c/bytecode.h | 9 +++- c/compile.c | 3 +- c/execute.c | 110 ++++++++++++++++++--------------------------- c/forkable_stack.h | 11 +++-- c/frame_layout.h | 81 +++++++++++++++++++++++++++++++++ c/opcode.c | 1 + c/opcode.h | 3 +- c/opcode_list.h | 2 + 8 files changed, 147 insertions(+), 73 deletions(-) create mode 100644 c/frame_layout.h diff --git a/c/bytecode.h b/c/bytecode.h index ddf1105a..a7141e4b 100644 --- a/c/bytecode.h +++ b/c/bytecode.h @@ -23,11 +23,18 @@ struct symbol_table { struct bytecode { uint16_t* code; int codelen; - int framesize; + + int nlocals; + int nclosures; + json_t* constants; struct symbol_table* globals; + + struct bytecode* subfunctions; + int nsubfunctions; }; void dump_disassembly(struct bytecode* code); void dump_operation(struct bytecode* bc, uint16_t* op); + #endif diff --git a/c/compile.c b/c/compile.c index cc344575..b102eeeb 100644 --- a/c/compile.c +++ b/c/compile.c @@ -274,7 +274,8 @@ struct bytecode* block_compile(struct symbol_table* syms, block b) { } free(stack_height); bc->constants = constant_pool; - bc->framesize = maxvar + 2; // FIXME: frames of size zero? + bc->nlocals = maxvar + 2; // FIXME: frames of size zero? + bc->nclosures = 0; bc->globals = syms; return bc; } diff --git a/c/execute.c b/c/execute.c index 44aaab3a..a97d80f2 100644 --- a/c/execute.c +++ b/c/execute.c @@ -10,6 +10,7 @@ #include "compile.h" #include "forkable_stack.h" +#include "frame_layout.h" typedef struct { @@ -52,34 +53,19 @@ typedef struct { stackval sv; } data_stk_elem; -data_stk_elem* stk_push_frame(int n) { - return forkable_stack_push(&data_stk, sizeof(data_stk_elem) * n); -} - -void stk_pop_frame(int n) { - forkable_stack_pop(&data_stk, sizeof(data_stk_elem) * n); -} - void stk_push(stackval val) { - data_stk_elem* s = stk_push_frame(1); + data_stk_elem* s = forkable_stack_push(&data_stk, sizeof(data_stk_elem)); s->sv = val; } stackval stk_pop() { - data_stk_elem* s = forkable_stack_peek(&data_stk, sizeof(data_stk_elem)); + data_stk_elem* s = forkable_stack_peek(&data_stk); stackval sv = s->sv; - forkable_stack_pop(&data_stk, sizeof(data_stk_elem)); + forkable_stack_pop(&data_stk); return sv; } - -typedef struct { - FORKABLE_STACK_HEADER; - struct bytecode* bc; - data_stk_elem* fp; - uint16_t* pc; -} call_stk_elem; -struct forkable_stack call_stk; +struct forkable_stack frame_stk; struct forkpoint { @@ -93,20 +79,20 @@ struct forkable_stack fork_stk; void stack_save(){ struct forkpoint* fork = forkable_stack_push(&fork_stk, sizeof(struct forkpoint)); forkable_stack_save(&data_stk, &fork->saved_data_stack); - forkable_stack_save(&call_stk, &fork->saved_call_stack); + forkable_stack_save(&frame_stk, &fork->saved_call_stack); } void stack_switch() { - struct forkpoint* fork = forkable_stack_peek(&fork_stk, sizeof(struct forkpoint)); + struct forkpoint* fork = forkable_stack_peek(&fork_stk); forkable_stack_switch(&data_stk, &fork->saved_data_stack); - forkable_stack_switch(&call_stk, &fork->saved_call_stack); + forkable_stack_switch(&frame_stk, &fork->saved_call_stack); } void stack_restore(){ - struct forkpoint* fork = forkable_stack_peek(&fork_stk, sizeof(struct forkpoint)); + struct forkpoint* fork = forkable_stack_peek(&fork_stk); forkable_stack_restore(&data_stk, &fork->saved_data_stack); - forkable_stack_restore(&call_stk, &fork->saved_call_stack); - forkable_stack_pop(&fork_stk, sizeof(struct forkpoint)); + forkable_stack_restore(&frame_stk, &fork->saved_call_stack); + forkable_stack_pop(&fork_stk); } #define stack_push stk_push @@ -115,29 +101,31 @@ void stack_restore(){ #define ON_BACKTRACK(op) ((op)+NUM_OPCODES) json_t* jq_next() { - assert(!forkable_stack_empty(&call_stk)); - call_stk_elem* ctx = forkable_stack_peek(&call_stk, sizeof(call_stk_elem)); - struct bytecode* bc = ctx->bc; - uint16_t* pc = ctx->pc; - data_stk_elem* fp = ctx->fp; - json_t* cpool = bc->constants; - json_t* cfunc_input[MAX_CFUNCTION_ARGS] = {0}; json_t* cfunc_output[MAX_CFUNCTION_ARGS] = {0}; + + + assert(!forkable_stack_empty(&frame_stk)); + uint16_t* pc = *frame_current_pc(&frame_stk); + int backtracking = 0; while (1) { - - dump_operation(bc, pc); + *frame_current_pc(&frame_stk) = pc; + dump_operation(frame_current_bytecode(&frame_stk), pc); uint16_t opcode = *pc++; printf("\t"); const struct opcode_description* opdesc = opcode_describe(opcode); - data_stk_elem* param = forkable_stack_peek(&data_stk, sizeof(data_stk_elem)); + data_stk_elem* param; for (int i=0; istack_in; i++) { + if (i == 0) { + param = forkable_stack_peek(&data_stk); + } else { + param = forkable_stack_peek_next(&data_stk, param); + } json_dumpf(param->sv.value, stdout, JSON_ENCODE_ANY); if (i < opdesc->stack_in-1) printf(" | "); - param = forkable_stack_peek_next(&data_stk, param, sizeof(data_stk_elem)); } if (backtracking) { @@ -152,7 +140,7 @@ json_t* jq_next() { default: assert(0 && "invalid instruction"); case LOADK: { - json_t* v = json_array_get(cpool, *pc++); + json_t* v = json_array_get(frame_current_bytecode(&frame_stk)->constants, *pc++); assert(v); stack_push(stackval_replace(stack_pop(), v)); break; @@ -205,17 +193,19 @@ json_t* jq_next() { case LOADV: { uint16_t v = *pc++; - stack_push(stackval_replace(stack_pop(), fp[v].sv.value)); + json_t** var = frame_local_var(frame_current(&frame_stk), v); + stack_push(stackval_replace(stack_pop(), *var)); break; } case STOREV: { uint16_t v = *pc++; + json_t** var = frame_local_var(frame_current(&frame_stk), v); stackval val = stack_pop(); printf("V%d = ", v); json_dumpf(val.value, stdout, JSON_ENCODE_ANY); printf("\n"); - fp[v].sv.value = val.value; + *var = val.value; break; } @@ -277,10 +267,7 @@ json_t* jq_next() { stack_save(); stack_push(array); stack_push(stackval_root(json_integer(idx+1))); - call_stk_elem* ctx = forkable_stack_push(&call_stk, sizeof(call_stk_elem)); - ctx->bc = bc; - ctx->fp = fp; - ctx->pc = pc - 1; + frame_push_backtrack(&frame_stk, frame_current_bytecode(&frame_stk), pc - 1); stack_switch(); stackval sv = {json_array_get(array.value, idx), @@ -296,22 +283,15 @@ json_t* jq_next() { return 0; } stack_restore(); - call_stk_elem* ctx = forkable_stack_peek(&call_stk, sizeof(call_stk_elem)); - bc = ctx->bc; - pc = ctx->pc; - fp = ctx->fp; - cpool = bc->constants; - forkable_stack_pop(&call_stk, sizeof(call_stk_elem)); + pc = *frame_current_pc(&frame_stk); + frame_pop(&frame_stk); backtracking = 1; break; } case FORK: { stack_save(); - call_stk_elem* ctx = forkable_stack_push(&call_stk, sizeof(call_stk_elem)); - ctx->bc = bc; - ctx->fp = fp; - ctx->pc = pc - 1; + frame_push_backtrack(&frame_stk, frame_current_bytecode(&frame_stk), pc - 1); stack_switch(); pc++; // skip offset this time break; @@ -324,17 +304,14 @@ json_t* jq_next() { case YIELD: { json_t* value = stack_pop().value; - call_stk_elem* ctx = forkable_stack_push(&call_stk, sizeof(call_stk_elem)); - ctx->bc = bc; - ctx->fp = fp; - ctx->pc = pc; + *frame_current_pc(&frame_stk) = pc; return value; } case CALL_BUILTIN_1_1: { stackval top = stack_pop(); cfunc_input[0] = top.value; - struct cfunction* func = &bc->globals->cfunctions[*pc++]; + struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++]; printf(" call %s\n", func->name); func->fptr(cfunc_input, cfunc_output); stack_push(stackval_replace(top, cfunc_output[0])); @@ -348,13 +325,19 @@ json_t* jq_next() { cfunc_input[0] = top.value; cfunc_input[1] = a; cfunc_input[2] = b; - struct cfunction* func = &bc->globals->cfunctions[*pc++]; + struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++]; printf(" call %s\n", func->name); func->fptr(cfunc_input, cfunc_output); stack_push(stackval_replace(top, cfunc_output[0])); break; } + + /* + case CALL_1_1: { + uint16_t nargs = *pc++; + } + */ } } @@ -363,16 +346,11 @@ json_t* jq_next() { void jq_init(struct bytecode* bc, json_t* input) { forkable_stack_init(&data_stk, sizeof(stackval) * 100); // FIXME: lower this number, see if it breaks - forkable_stack_init(&call_stk, 1024); // FIXME: lower this number, see if it breaks + forkable_stack_init(&frame_stk, 1024); // FIXME: lower this number, see if it breaks forkable_stack_init(&fork_stk, 1024); // FIXME: lower this number, see if it breaks - data_stk_elem* frame = stk_push_frame(bc->framesize); - stack_push(stackval_root(input)); - call_stk_elem* ctx = forkable_stack_push(&call_stk, sizeof(call_stk_elem)); - ctx->pc = bc->code; - ctx->bc = bc; - ctx->fp = frame; + frame_push(&frame_stk, bc); } void run_program(struct bytecode* bc) { diff --git a/c/forkable_stack.h b/c/forkable_stack.h index 5b8ec8ad..88a280f2 100644 --- a/c/forkable_stack.h +++ b/c/forkable_stack.h @@ -1,3 +1,5 @@ +#ifndef FORKABLE_STACK_H +#define FORKABLE_STACK_H #include #include #include @@ -65,21 +67,21 @@ static void* forkable_stack_push(struct forkable_stack* s, size_t size) { return ret; } -static void* forkable_stack_peek(struct forkable_stack* s, size_t size) { +static void* forkable_stack_peek(struct forkable_stack* s) { assert(!forkable_stack_empty(s)); forkable_stack_check(s); return (void*)(s->stk + s->pos); } -static void* forkable_stack_peek_next(struct forkable_stack* s, void* top, size_t size) { +static void* forkable_stack_peek_next(struct forkable_stack* s, void* top) { forkable_stack_check(s); struct forkable_stack_header* elem = top; return (void*)(s->stk + elem->next); } -static void forkable_stack_pop(struct forkable_stack* s, size_t size) { +static void forkable_stack_pop(struct forkable_stack* s) { forkable_stack_check(s); - struct forkable_stack_header* elem = forkable_stack_peek(s, size); + struct forkable_stack_header* elem = forkable_stack_peek(s); s->pos = elem->next; } @@ -114,3 +116,4 @@ static void forkable_stack_restore(struct forkable_stack* s, struct forkable_sta s->savedlimit = state->prevlimit; forkable_stack_check(s); } +#endif diff --git a/c/frame_layout.h b/c/frame_layout.h new file mode 100644 index 00000000..55919f8a --- /dev/null +++ b/c/frame_layout.h @@ -0,0 +1,81 @@ +#ifndef FRAME_LAYOUT_H +#include "forkable_stack.h" +#include "bytecode.h" +#include + +struct closure { + struct bytecode* bc; + uint16_t* pc; +}; + +typedef union frame_elem { + FORKABLE_STACK_HEADER; + struct closure closure; + json_t* jsonval; +} *frame_ptr; + +/* + * Frame layout + * fr[0] - FORKABLE_STACK_HEADER (next pointer) + * fr[1] - self (used to store return addresses, etc) + * fr[2...nclosures+2] - closure params + * fr[nclosures+2..nclosures+nlocals+2] - local variables + */ + +static int frame_size(struct bytecode* bc) { + return sizeof(union frame_elem) * (bc->nclosures + bc->nlocals + 2); +} + +static struct closure* frame_self(frame_ptr fr) { + return &fr[1].closure; +} + +static struct closure* frame_closure_arg(frame_ptr fr, int closure) { + assert(closure >= 0); + assert(closure < frame_self(fr)->bc->nclosures); + return &fr[2+closure].closure; +} + +static json_t** frame_local_var(frame_ptr fr, int var) { + assert(var >= 0); + assert(var < frame_self(fr)->bc->nlocals); + return &fr[2 + frame_self(fr)->bc->nclosures + var].jsonval; +} + + +static frame_ptr frame_current(struct forkable_stack* stk) { + frame_ptr fp = forkable_stack_peek(stk); + struct bytecode* bc = frame_self(fp)->bc; + assert(frame_self(fp)->pc >= bc->code && frame_self(fp)->pc < bc->code + bc->codelen); + return fp; +} + +static struct bytecode* frame_current_bytecode(struct forkable_stack* stk) { + return frame_self(frame_current(stk))->bc; +} +static uint16_t** frame_current_pc(struct forkable_stack* stk) { + return &frame_self(frame_current(stk))->pc; +} + + + + +static void frame_push(struct forkable_stack* stk, struct bytecode* bc) { + frame_ptr fp = forkable_stack_push(stk, frame_size(bc)); + frame_self(fp)->bc = bc; + frame_self(fp)->pc = bc->code; +} + +static void frame_push_backtrack(struct forkable_stack* stk, + struct bytecode* bc, uint16_t* pc) { + frame_ptr fp = forkable_stack_push(stk, sizeof(union frame_elem) * 2); + frame_self(fp)->bc = bc; + frame_self(fp)->pc = pc; +} + + +static void frame_pop(struct forkable_stack* stk) { + forkable_stack_pop(stk); +} + +#endif diff --git a/c/opcode.c b/c/opcode.c index b14e0db6..92bbcd29 100644 --- a/c/opcode.c +++ b/c/opcode.c @@ -5,6 +5,7 @@ #define VARIABLE (OP_HAS_IMMEDIATE | OP_HAS_VARIABLE) #define BRANCH (OP_HAS_IMMEDIATE | OP_HAS_BRANCH) #define CFUNC (OP_HAS_IMMEDIATE | OP_HAS_SYMBOL | OP_HAS_CFUNC) +#define UFUNC (OP_HAS_IMMEDIATE | OP_HAS_UFUNC) #define OP(name, imm, in, out) \ {name, #name, imm, in, out}, diff --git a/c/opcode.h b/c/opcode.h index 797e6a96..36d41920 100644 --- a/c/opcode.h +++ b/c/opcode.h @@ -19,7 +19,8 @@ enum { OP_HAS_VARIABLE = 4, OP_HAS_BRANCH = 8, OP_HAS_SYMBOL = 16, - OP_HAS_CFUNC = 32 + OP_HAS_CFUNC = 32, + OP_HAS_UFUNC = 64, }; struct opcode_description { opcode op; diff --git a/c/opcode_list.h b/c/opcode_list.h index 2fe3f8a8..d3bfb983 100644 --- a/c/opcode_list.h +++ b/c/opcode_list.h @@ -16,3 +16,5 @@ OP(INSERT, NONE, 4, 2) OP(CALL_BUILTIN_1_1, CFUNC, 1, 1) OP(CALL_BUILTIN_3_1, CFUNC, 3, 1) + +OP(CALL_1_1, UFUNC, 1, 1) From c128c2029e863a6f06dbf90a811e221a8ffdccaa Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 21 Aug 2012 18:14:13 +0100 Subject: [PATCH 006/284] First pass at functions + tests --- c/Makefile | 2 +- c/bytecode.c | 43 ++++++++-- c/bytecode.h | 13 ++- c/compile.c | 208 +++++++++++++++++++++++++++++++++------------ c/compile.h | 5 +- c/execute.c | 42 +++++++-- c/forkable_stack.h | 15 ++++ c/frame_layout.h | 43 +++++++--- c/lexer.l | 1 + c/main.c | 5 +- c/opcode.c | 6 +- c/opcode.h | 4 + c/opcode_list.h | 5 ++ c/parser.y | 15 +++- c/testdata | 143 +++++++++++++++++++++++++++++++ 15 files changed, 461 insertions(+), 89 deletions(-) create mode 100644 c/testdata diff --git a/c/Makefile b/c/Makefile index ca20397f..01c3b540 100644 --- a/c/Makefile +++ b/c/Makefile @@ -14,7 +14,7 @@ lexer.yy.c: lexer.l lexer.yy.h: lexer.yy.c parser.tab.c: parser.y lexer.yy.h - bison -W -d parser.y + bison -W -d parser.y -v --report-file=parser.info parser.tab.h: parser.tab.c parsertest: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c diff --git a/c/bytecode.c b/c/bytecode.c index 477d3aa4..82e38f4c 100644 --- a/c/bytecode.c +++ b/c/bytecode.c @@ -4,12 +4,29 @@ #include "bytecode.h" #include "opcode.h" -void dump_disassembly(struct bytecode* bc) { +static int bytecode_operation_length(uint16_t* codeptr) { + if (opcode_describe(*codeptr)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) { + return 2 + codeptr[1] * 2; + } else { + return opcode_length(*codeptr); + } +} + +void dump_disassembly(int indent, struct bytecode* bc) { + dump_code(indent, bc); + for (int i=0; insubfunctions; i++) { + printf("%*ssubfn[%d]:\n", indent, "", i); + dump_disassembly(indent+2, bc->subfunctions[i]); + } +} + +void dump_code(int indent, struct bytecode* bc) { int pc = 0; while (pc < bc->codelen) { + printf("%*s", indent, ""); dump_operation(bc, bc->code + pc); printf("\n"); - pc += opcode_length(bc->code[pc]); + pc += bytecode_operation_length(bc->code + pc); } } @@ -20,16 +37,28 @@ void dump_operation(struct bytecode* bc, uint16_t* codeptr) { printf("%s", op->name); if (op->flags & OP_HAS_IMMEDIATE) { uint16_t imm = bc->code[pc++]; - printf(" "); - if (op->flags & OP_HAS_BRANCH) { - printf("%04d", pc + imm); + if (op->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) { + for (int i=0; icode[pc++]; + uint16_t idx = bc->code[pc++]; + if (idx & ARG_NEWCLOSURE) { + printf(" subfn[%d]", idx & ~ARG_NEWCLOSURE); + } else { + printf(" param[%d]", idx); + } + if (level) { + printf("^%d", level); + } + } + } else if (op->flags & OP_HAS_BRANCH) { + printf(" %04d", pc + imm); } else if (op->flags & OP_HAS_CONSTANT) { json_dumpf(json_array_get(bc->constants, imm), stdout, JSON_ENCODE_ANY); } else if (op->flags & OP_HAS_VARIABLE) { - printf("v%d", imm); + printf(" v%d", imm); } else { - printf("%d", imm); + printf(" %d", imm); } } } diff --git a/c/bytecode.h b/c/bytecode.h index a7141e4b..b1146ad7 100644 --- a/c/bytecode.h +++ b/c/bytecode.h @@ -19,6 +19,12 @@ struct symbol_table { int ncfunctions; }; +// The bytecode format matters in: +// execute.c - interpreter +// compile.c - compiler +// bytecode.c - disassembler + +#define ARG_NEWCLOSURE 0x1000 struct bytecode { uint16_t* code; @@ -30,11 +36,14 @@ struct bytecode { json_t* constants; struct symbol_table* globals; - struct bytecode* subfunctions; + struct bytecode** subfunctions; int nsubfunctions; + + struct bytecode* parent; }; -void dump_disassembly(struct bytecode* code); +void dump_disassembly(int, struct bytecode* code); +void dump_code(int, struct bytecode* code); void dump_operation(struct bytecode* bc, uint16_t* op); #endif diff --git a/c/compile.c b/c/compile.c index b102eeeb..89446330 100644 --- a/c/compile.c +++ b/c/compile.c @@ -14,11 +14,23 @@ struct inst { uint16_t intval; struct inst* target; json_t* constant; - char* symbol; } imm; - struct inst* var_binding; - int var_frame_idx; + // Binding + // An instruction requiring binding (for parameters/variables) + // is in one of three states: + // bound_by = NULL - Unbound free variable + // bound_by = self - This instruction binds a variable + // bound_by = other - Uses variable bound by other instruction + // The immediate field is generally not meaningful until instructions + // are bound, and even then only for instructions which bind. + struct inst* bound_by; + char* symbol; + block subfn; + + // This instruction is compiled as part of which function? + // (only used during block_compile) + struct bytecode* compiled; int bytecode_pos; // position just after this insn }; @@ -28,15 +40,16 @@ static inst* inst_new(opcode op) { i->next = i->prev = 0; i->op = op; i->bytecode_pos = -1; - i->var_binding = 0; - i->var_frame_idx = 0; + i->bound_by = 0; + i->symbol = 0; + i->subfn = gen_noop(); return i; } static void inst_free(struct inst* i) { - if (opcode_describe(i->op)->flags & - (OP_HAS_SYMBOL | OP_HAS_VARIABLE)) { - free(i->imm.symbol); + free(i->symbol); + if (opcode_describe(i->op)->flags & OP_HAS_BLOCK) { + block_free(i->subfn); } free(i); } @@ -89,25 +102,56 @@ void inst_set_target(block b, block target) { block gen_op_var_unbound(opcode op, const char* name) { assert(opcode_describe(op)->flags & OP_HAS_VARIABLE); inst* i = inst_new(op); - i->imm.symbol = strdup(name); + i->symbol = strdup(name); return inst_block(i); } block gen_op_var_bound(opcode op, block binder) { + assert(opcode_describe(op)->flags & OP_HAS_VARIABLE); assert(binder.first); assert(binder.first == binder.last); - block b = gen_op_var_unbound(op, binder.first->imm.symbol); - b.first->var_binding = binder.first; + block b = gen_op_var_unbound(op, binder.first->symbol); + b.first->bound_by = binder.first; return b; } block gen_op_symbol(opcode op, const char* sym) { assert(opcode_describe(op)->flags & OP_HAS_SYMBOL); inst* i = inst_new(op); - i->imm.symbol = strdup(sym); + i->symbol = strdup(sym); return inst_block(i); } +block gen_op_block_defn(opcode op, const char* name, block block) { + assert(opcode_describe(op)->flags & OP_IS_CALL_PSEUDO); + assert(opcode_describe(op)->flags & OP_HAS_BLOCK); + inst* i = inst_new(op); + i->subfn = block; + i->symbol = strdup(name); + return inst_block(i); +} + +block gen_op_block_unbound(opcode op, const char* name) { + assert(opcode_describe(op)->flags & OP_IS_CALL_PSEUDO); + inst* i = inst_new(op); + i->symbol = strdup(name); + return inst_block(i); +} + + +block gen_op_call(opcode op, block arglist) { + assert(opcode_describe(op)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST); + inst* i = inst_new(op); + int nargs = 0; + for (inst* curr = arglist.first; curr; curr = curr->next) { + assert(opcode_describe(curr->op)->flags & OP_IS_CALL_PSEUDO); + nargs++; + } + assert(nargs < 100); //FIXME + i->imm.intval = nargs; + return block_join(inst_block(i), arglist); +} + static void inst_join(inst* a, inst* b) { assert(a && b); assert(!a->next); @@ -133,22 +177,31 @@ block block_join(block a, block b) { return c; } -block block_bind(block binder, block body) { +static void block_bind_subblock(block binder, block body, int bindflags) { assert(binder.first); assert(binder.first == binder.last); - assert(opcode_describe(binder.first->op)->flags & OP_HAS_VARIABLE); - assert(binder.first->imm.symbol); - assert(binder.first->var_binding == 0); + assert((opcode_describe(binder.first->op)->flags & bindflags) == bindflags); + assert(binder.first->symbol); + assert(binder.first->bound_by == 0 || binder.first->bound_by == binder.first); - binder.first->var_binding = binder.first; + binder.first->bound_by = binder.first; for (inst* i = body.first; i; i = i->next) { - if (opcode_describe(i->op)->flags & OP_HAS_VARIABLE && - i->var_binding == 0 && - !strcmp(i->imm.symbol, binder.first->imm.symbol)) { - // bind this variable - i->var_binding = binder.first; + int flags = opcode_describe(i->op)->flags; + if ((flags & bindflags) == bindflags && + i->bound_by == 0 && + !strcmp(i->symbol, binder.first->symbol)) { + // bind this instruction + i->bound_by = binder.first; + } + if (flags & OP_HAS_BLOCK) { + block_bind_subblock(binder, i->subfn, bindflags); } } +} + +block block_bind(block binder, block body, int bindflags) { + bindflags |= OP_HAS_BINDING; + block_bind_subblock(binder, body, bindflags); return block_join(binder, body); } @@ -180,7 +233,7 @@ block gen_collect(block expr) { block_append(&c, gen_op_simple(DUP)); block_append(&c, gen_op_const(LOADK, json_array())); block array_var = block_bind(gen_op_var_unbound(STOREV, "collect"), - gen_noop()); + gen_noop(), OP_HAS_VARIABLE); block_append(&c, array_var); block tail = {0}; @@ -204,64 +257,108 @@ block gen_else(block a, block b) { assert(0); } +static uint16_t nesting_level(struct bytecode* bc, inst* target) { + uint16_t level = 0; + assert(bc && target->compiled); + while (bc && target->compiled != bc) { + level++; + bc = bc->parent; + } + assert(bc && bc == target->compiled); + return level; +} -struct bytecode* block_compile(struct symbol_table* syms, block b) { - inst* curr = b.first; +static void compile(struct bytecode* bc, block b) { int pos = 0; int var_frame_idx = 0; - for (; curr; curr = curr->next) { + bc->nsubfunctions = 0; + for (inst* curr = b.first; curr; curr = curr->next) { if (!curr->next) assert(curr == b.last); pos += opcode_length(curr->op); curr->bytecode_pos = pos; - if (opcode_describe(curr->op)->flags & OP_HAS_VARIABLE) { - assert(curr->var_binding && "unbound variable"); - if (curr->var_binding == curr) { - curr->var_frame_idx = var_frame_idx++; - } + curr->compiled = bc; + + int opflags = opcode_describe(curr->op)->flags; + if (opflags & OP_HAS_BINDING) { + assert(curr->bound_by && "unbound term"); + } + if ((opflags & OP_HAS_VARIABLE) && + curr->bound_by == curr) { + curr->imm.intval = var_frame_idx++; + } + if (opflags & OP_HAS_BLOCK) { + assert(curr->bound_by == curr); + curr->imm.intval = bc->nsubfunctions++; } } - struct bytecode* bc = malloc(sizeof(struct bytecode)); + if (bc->nsubfunctions) { + bc->subfunctions = malloc(sizeof(struct bytecode*) * bc->nsubfunctions); + for (inst* curr = b.first; curr; curr = curr->next) { + if (!(opcode_describe(curr->op)->flags & OP_HAS_BLOCK)) + continue; + struct bytecode* subfn = malloc(sizeof(struct bytecode)); + bc->subfunctions[curr->imm.intval] = subfn; + subfn->globals = bc->globals; + subfn->parent = bc; + compile(subfn, curr->subfn); + } + } else { + bc->subfunctions = 0; + } bc->codelen = pos; uint16_t* code = malloc(sizeof(uint16_t) * bc->codelen); bc->code = code; - int* stack_height = malloc(sizeof(int) * (bc->codelen + 1)); - for (int i = 0; icodelen + 1; i++) stack_height[i] = -1; pos = 0; json_t* constant_pool = json_array(); int maxvar = -1; - int curr_stack_height = 1; - for (curr = b.first; curr; curr = curr->next) { + for (inst* curr = b.first; curr; curr = curr->next) { + if (curr->op == CLOSURE_CREATE) { + // CLOSURE_CREATE opcodes define closures for use later in the + // codestream. They generate no code. + + // FIXME: make the above true :) + code[pos++] = DUP; + code[pos++] = POP; + continue; + } const struct opcode_description* op = opcode_describe(curr->op); - if (curr_stack_height < op->stack_in) { - printf("Stack underflow at %04d\n", curr->bytecode_pos); - } - if (stack_height[curr->bytecode_pos] != -1 && - stack_height[curr->bytecode_pos] != curr_stack_height) { - // FIXME: not sure this is right at all :( - printf("Inconsistent stack heights at %04d %s\n", curr->bytecode_pos, op->name); - } - curr_stack_height -= op->stack_in; - curr_stack_height += op->stack_out; code[pos++] = curr->op; int opflags = op->flags; - if (opflags & OP_HAS_CONSTANT) { + assert(!(op->flags & OP_IS_CALL_PSEUDO)); + if (opflags & OP_HAS_VARIABLE_LENGTH_ARGLIST) { + int nargs = curr->imm.intval; + assert(nargs > 0); + code[pos++] = (uint16_t)nargs; + for (int i=0; inext; + assert(curr && opcode_describe(curr->op)->flags & OP_IS_CALL_PSEUDO); + code[pos++] = nesting_level(bc, curr->bound_by); + switch (curr->bound_by->op) { + default: assert(0 && "Unknown type of argument"); + case CLOSURE_CREATE: + code[pos++] = curr->bound_by->imm.intval | ARG_NEWCLOSURE; + break; + } + } + } else if (opflags & OP_HAS_CONSTANT) { code[pos++] = json_array_size(constant_pool); json_array_append(constant_pool, curr->imm.constant); } else if (opflags & OP_HAS_VARIABLE) { - uint16_t var = (uint16_t)curr->var_binding->var_frame_idx; + // no closing over variables yet + assert(curr->bound_by->compiled == bc); + uint16_t var = (uint16_t)curr->bound_by->imm.intval; code[pos++] = var; if (var > maxvar) maxvar = var; } else if (opflags & OP_HAS_BRANCH) { assert(curr->imm.target->bytecode_pos != -1); assert(curr->imm.target->bytecode_pos > pos); // only forward branches code[pos] = curr->imm.target->bytecode_pos - (pos + 1); - stack_height[curr->imm.target->bytecode_pos] = curr_stack_height; pos++; } else if (opflags & OP_HAS_CFUNC) { - assert(curr->imm.symbol); + assert(curr->symbol); int found = 0; - for (int i=0; incfunctions; i++) { - if (!strcmp(curr->imm.symbol, syms->cfunctions[i].name)) { + for (int i=0; iglobals->ncfunctions; i++) { + if (!strcmp(curr->symbol, bc->globals->cfunctions[i].name)) { code[pos++] = i; found = 1; break; @@ -272,11 +369,16 @@ struct bytecode* block_compile(struct symbol_table* syms, block b) { code[pos++] = curr->imm.intval; } } - free(stack_height); bc->constants = constant_pool; bc->nlocals = maxvar + 2; // FIXME: frames of size zero? bc->nclosures = 0; +} + +struct bytecode* block_compile(struct symbol_table* syms, block b) { + struct bytecode* bc = malloc(sizeof(struct bytecode)); + bc->parent = 0; bc->globals = syms; + compile(bc, b); return bc; } diff --git a/c/compile.h b/c/compile.h index 0ba54f15..d72ddcef 100644 --- a/c/compile.h +++ b/c/compile.h @@ -17,6 +17,9 @@ block gen_op_const(opcode op, json_t* constant); block gen_op_target(opcode op, block target); block gen_op_var_unbound(opcode op, const char* name); block gen_op_var_bound(opcode op, block binder); +block gen_op_block_defn(opcode op, const char* name, block block); +block gen_op_block_unbound(opcode op, const char* name); +block gen_op_call(opcode op, block arglist); block gen_op_symbol(opcode op, const char* name); block gen_subexp(block a); @@ -27,7 +30,7 @@ block gen_else(block a, block b); void block_append(block* b, block b2); block block_join(block a, block b); -block block_bind(block binder, block body); +block block_bind(block binder, block body, int bindflags); struct bytecode* block_compile(struct symbol_table*, block); diff --git a/c/execute.c b/c/execute.c index a97d80f2..8bd8ec3c 100644 --- a/c/execute.c +++ b/c/execute.c @@ -95,6 +95,18 @@ void stack_restore(){ forkable_stack_pop(&fork_stk); } +static struct closure make_closure(struct forkable_stack* stk, frame_ptr fr, uint16_t* pc) { + uint16_t level = *pc++; + uint16_t idx = *pc++; + fr = frame_get_level(stk, fr, level); + if (idx & ARG_NEWCLOSURE) { + int subfn_idx = idx & ~ARG_NEWCLOSURE; + assert(subfn_idx < frame_self(fr)->bc->nsubfunctions); + return closure_new(stk, frame_self(fr)->bc->subfunctions[subfn_idx]); + } else { + return *frame_closure_arg(fr, idx); + } +} #define stack_push stk_push #define stack_pop stk_pop @@ -267,7 +279,7 @@ json_t* jq_next() { stack_save(); stack_push(array); stack_push(stackval_root(json_integer(idx+1))); - frame_push_backtrack(&frame_stk, frame_current_bytecode(&frame_stk), pc - 1); + frame_push_backtrack(&frame_stk, pc - 1); stack_switch(); stackval sv = {json_array_get(array.value, idx), @@ -291,7 +303,7 @@ json_t* jq_next() { case FORK: { stack_save(); - frame_push_backtrack(&frame_stk, frame_current_bytecode(&frame_stk), pc - 1); + frame_push_backtrack(&frame_stk, pc - 1); stack_switch(); pc++; // skip offset this time break; @@ -332,13 +344,27 @@ json_t* jq_next() { break; } - /* case CALL_1_1: { - uint16_t nargs = *pc++; - + uint16_t nclosures = *pc++; + *frame_current_pc(&frame_stk) = pc + nclosures * 2; + frame_ptr new_frame = frame_push(&frame_stk, + make_closure(&frame_stk, frame_current(&frame_stk), pc)); + pc += 2; + frame_ptr old_frame = forkable_stack_peek_next(&frame_stk, new_frame); + for (int i=0; isavedlimit = state->prevlimit; forkable_stack_check(s); } + +typedef int stack_idx; + +static stack_idx forkable_stack_to_idx(struct forkable_stack* s, void* ptr) { + char* item = ptr; + int pos = item - s->stk; + assert(pos >= 0 && pos < s->length); + return s->length - pos; +} + +static void* forkable_stack_from_idx(struct forkable_stack* s, stack_idx idx) { + assert(idx >= 1 && idx <= s->length); + return &s->stk[s->length - idx]; +} + #endif diff --git a/c/frame_layout.h b/c/frame_layout.h index 55919f8a..373c2b86 100644 --- a/c/frame_layout.h +++ b/c/frame_layout.h @@ -6,6 +6,7 @@ struct closure { struct bytecode* bc; uint16_t* pc; + stack_idx env; }; typedef union frame_elem { @@ -57,23 +58,41 @@ static uint16_t** frame_current_pc(struct forkable_stack* stk) { return &frame_self(frame_current(stk))->pc; } - - - -static void frame_push(struct forkable_stack* stk, struct bytecode* bc) { - frame_ptr fp = forkable_stack_push(stk, frame_size(bc)); - frame_self(fp)->bc = bc; - frame_self(fp)->pc = bc->code; +static frame_ptr frame_get_parent(struct forkable_stack* stk, frame_ptr fr) { + return forkable_stack_from_idx(stk, frame_self(fr)->env); } -static void frame_push_backtrack(struct forkable_stack* stk, - struct bytecode* bc, uint16_t* pc) { +static frame_ptr frame_get_level(struct forkable_stack* stk, frame_ptr fr, int level) { + for (int i=0; icode, -1}; + return cl; +} +static struct closure closure_new(struct forkable_stack* stk, struct bytecode* bc) { + struct closure cl = {bc, bc->code, + forkable_stack_to_idx(stk, frame_current(stk))}; + return cl; +} + +static frame_ptr frame_push(struct forkable_stack* stk, struct closure cl) { + frame_ptr fp = forkable_stack_push(stk, frame_size(cl.bc)); + *frame_self(fp) = cl; + return fp; +} + +static frame_ptr frame_push_backtrack(struct forkable_stack* stk, uint16_t* pc) { + struct closure curr = *frame_self(frame_current(stk)); frame_ptr fp = forkable_stack_push(stk, sizeof(union frame_elem) * 2); - frame_self(fp)->bc = bc; - frame_self(fp)->pc = pc; + curr.pc = pc; + *frame_self(fp) = curr; + return fp; } - static void frame_pop(struct forkable_stack* stk) { forkable_stack_pop(stk); } diff --git a/c/lexer.l b/c/lexer.l index 42103c40..abf33263 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -11,6 +11,7 @@ "==" { return EQ; } "as" { return AS; } +"def" { return DEF; } "."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];} [[:digit:]]+ { yylval->num = atoi(yytext); return NUMBER;} diff --git a/c/main.c b/c/main.c index 5017d9fa..f8ea2149 100644 --- a/c/main.c +++ b/c/main.c @@ -32,6 +32,9 @@ void run_tests() { block_append(&program, gen_op_simple(BACKTRACK)); struct bytecode* bc = block_compile(&builtins, program); block_free(program); + printf("Disassembly:\n"); + dump_disassembly(2, bc); + printf("\n"); fgets(buf, sizeof(buf), testdata); json_t* input = json_loads(buf, JSON_DECODE_ANY, 0); jq_init(bc, input); @@ -76,7 +79,7 @@ int main(int argc, char* argv[]) { block_append(&blk, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK))); struct bytecode* bc = block_compile(&builtins, blk); block_free(blk); - dump_disassembly(bc); + dump_disassembly(0, bc); printf("\n"); run_program(bc); } diff --git a/c/opcode.c b/c/opcode.c index 92bbcd29..ff41f86c 100644 --- a/c/opcode.c +++ b/c/opcode.c @@ -2,10 +2,12 @@ #define NONE 0 #define CONSTANT (OP_HAS_IMMEDIATE | OP_HAS_CONSTANT) -#define VARIABLE (OP_HAS_IMMEDIATE | OP_HAS_VARIABLE) +#define VARIABLE (OP_HAS_IMMEDIATE | OP_HAS_VARIABLE | OP_HAS_BINDING) #define BRANCH (OP_HAS_IMMEDIATE | OP_HAS_BRANCH) #define CFUNC (OP_HAS_IMMEDIATE | OP_HAS_SYMBOL | OP_HAS_CFUNC) -#define UFUNC (OP_HAS_IMMEDIATE | OP_HAS_UFUNC) +#define UFUNC (OP_HAS_IMMEDIATE | OP_HAS_UFUNC | OP_HAS_VARIABLE_LENGTH_ARGLIST) +#define CLOSURE_DEFINE (OP_HAS_IMMEDIATE | OP_HAS_BLOCK | OP_IS_CALL_PSEUDO | OP_HAS_BINDING) +#define CLOSURE_REF (OP_HAS_IMMEDIATE | OP_IS_CALL_PSEUDO | OP_HAS_BINDING) #define OP(name, imm, in, out) \ {name, #name, imm, in, out}, diff --git a/c/opcode.h b/c/opcode.h index 36d41920..262ecb3b 100644 --- a/c/opcode.h +++ b/c/opcode.h @@ -21,6 +21,10 @@ enum { OP_HAS_SYMBOL = 16, OP_HAS_CFUNC = 32, OP_HAS_UFUNC = 64, + OP_IS_CALL_PSEUDO = 128, + OP_HAS_VARIABLE_LENGTH_ARGLIST = 256, + OP_HAS_BLOCK = 512, + OP_HAS_BINDING = 1024, }; struct opcode_description { opcode op; diff --git a/c/opcode_list.h b/c/opcode_list.h index d3bfb983..c54e1fda 100644 --- a/c/opcode_list.h +++ b/c/opcode_list.h @@ -18,3 +18,8 @@ OP(CALL_BUILTIN_1_1, CFUNC, 1, 1) OP(CALL_BUILTIN_3_1, CFUNC, 3, 1) OP(CALL_1_1, UFUNC, 1, 1) +OP(RET, NONE, 1, 1) + +OP(CLOSURE_PARAM, CLOSURE_REF, 0, 0) +OP(CLOSURE_REF, CLOSURE_REF, 0, 0) +OP(CLOSURE_CREATE, CLOSURE_DEFINE, 0, 0) diff --git a/c/parser.y b/c/parser.y index 393f7a83..ca82fcd5 100644 --- a/c/parser.y +++ b/c/parser.y @@ -20,10 +20,14 @@ %token IDENT %token NUMBER + /* revolting hack */ +%left ';' + %left '|' %left ',' %token EQ "==" %token AS "as" +%token DEF "def" %nonassoc EQ %left '+' @@ -55,12 +59,16 @@ static block gen_index(block obj, block key) { %% program: Exp { *answer = $1; } - Exp: +"def" IDENT ':' Exp ';' Exp { + block body = block_join($4, gen_op_simple(RET)); + $$ = block_bind(gen_op_block_defn(CLOSURE_CREATE, $2, body), $6, OP_IS_CALL_PSEUDO); +} | + Term "as" '$' IDENT '|' Exp { $$ = gen_op_simple(DUP); block_append(&$$, $1); - block_append(&$$, block_bind(gen_op_var_unbound(STOREV, $4), $6)); + block_append(&$$, block_bind(gen_op_var_unbound(STOREV, $4), $6, OP_HAS_VARIABLE)); } | Exp '|' Exp { @@ -132,6 +140,9 @@ IDENT { } | '$' IDENT { $$ = gen_op_var_unbound(LOADV, $2); +} | +'$' '$' IDENT { + $$ = gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, $3)); } MkDict: diff --git a/c/testdata b/c/testdata new file mode 100644 index 00000000..cc4d17bc --- /dev/null +++ b/c/testdata @@ -0,0 +1,143 @@ +# Tests are groups of three lines: program, input, expected output +# Blank lines and lines starting with # are ignored + +# +# Simple value tests to check parser. Input is irrelevant +# + +true +null +true + +false +null +false + +# null +# 42 +# null + +1 +null +1 + +# FIXME: much more number testing needed + +{} +null +{} + +[] +null +[] + +# FIXME: string literals + +# +# Dictionary construction syntax +# + +{a: 1} +null +{"a":1} + +# FIXME: string literals + +# +# Field access, piping +# + +.foo +{"foo": 42, "bar": 43} +42 + +.foo | .bar +{"foo": {"bar": 42}, "bar": "badvalue"} +42 + +.foo.bar +{"foo": {"bar": 42}, "bar": "badvalue"} +42 + + +# FIXME strings +# .["foo"].bar +# {"foo": {"bar": 42}, "bar": "badvalue"} +# 42 + + +# +# Multiple outputs, iteration +# + +.[] +[1,2,3] +1 +2 +3 + +[(.,1),((.,.[]),(2,3))] +["a","b"] +[["a","b"],1,["a","b"],"a","b",2,3] + +[([5,5][]),.,.[]] +[1,2,3] +[5,5,[1,2,3],1,2,3] + +{x: (1,2)},{x:3} | .x +null +1 +2 +3 + +# +# Variables +# + +1 as $x | 2 as $y | [$x,$y,$x] +null +[1,2,1] + +[1,2,3][] as $x | [[4,5,6,7][$x]] +null +[5] +[6] +[7] + +1 as $x | [$x,$x,$x as $x | $x] +null +[1,1,1] + +# [.,(.[] | {x:.},.),.,.[]] + +# +# Builtin functions +# + +# FIXME: floats vs. integer + +1+1 +null +2.0 + +.+4 +15 +19.0 + +[1,2,3] + [.] +null +[1,2,3,null] + +# +# User-defined functions +# Oh god. +# + +def f: . + 1; def g: def g: . + 100; $$f | $$g | $$f; ($$f | $$g), $$g +3.0 +106.0 +105.0 + +[[100,200][] as $x | def f: . + $x; $$f | $$f | $$f] +1 +[300.0, 600.0] \ No newline at end of file From 79d81f4beef13612241be3fe16c29a65272a4bf6 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 21 Aug 2012 18:24:38 +0100 Subject: [PATCH 007/284] Closures over variables --- c/bytecode.c | 9 +++++++-- c/compile.c | 3 +-- c/execute.c | 8 ++++++-- c/opcode.c | 2 +- c/opcode.h | 5 ++++- c/testdata | 2 +- 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/c/bytecode.c b/c/bytecode.c index 82e38f4c..08d7fff3 100644 --- a/c/bytecode.c +++ b/c/bytecode.c @@ -35,7 +35,7 @@ void dump_operation(struct bytecode* bc, uint16_t* codeptr) { printf("%04d ", pc); const struct opcode_description* op = opcode_describe(bc->code[pc++]); printf("%s", op->name); - if (op->flags & OP_HAS_IMMEDIATE) { + if (op->flags & OP_HAS_IMMEDIATE || op->flags & OP_HAS_DOUBLE_IMMEDIATE) { uint16_t imm = bc->code[pc++]; if (op->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) { for (int i=0; iflags & OP_HAS_BRANCH) { printf(" %04d", pc + imm); } else if (op->flags & OP_HAS_CONSTANT) { + printf(" "); json_dumpf(json_array_get(bc->constants, imm), stdout, JSON_ENCODE_ANY); } else if (op->flags & OP_HAS_VARIABLE) { - printf(" v%d", imm); + uint16_t v = bc->code[pc++]; + printf(" v%d", v); + if (imm) { + printf("^%d", imm); + } } else { printf(" %d", imm); } diff --git a/c/compile.c b/c/compile.c index 89446330..cf5834b2 100644 --- a/c/compile.c +++ b/c/compile.c @@ -344,8 +344,7 @@ static void compile(struct bytecode* bc, block b) { code[pos++] = json_array_size(constant_pool); json_array_append(constant_pool, curr->imm.constant); } else if (opflags & OP_HAS_VARIABLE) { - // no closing over variables yet - assert(curr->bound_by->compiled == bc); + code[pos++] = nesting_level(bc, curr->bound_by); uint16_t var = (uint16_t)curr->bound_by->imm.intval; code[pos++] = var; if (var > maxvar) maxvar = var; diff --git a/c/execute.c b/c/execute.c index 8bd8ec3c..5245682b 100644 --- a/c/execute.c +++ b/c/execute.c @@ -204,15 +204,19 @@ json_t* jq_next() { } case LOADV: { + uint16_t level = *pc++; uint16_t v = *pc++; - json_t** var = frame_local_var(frame_current(&frame_stk), v); + frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); + json_t** var = frame_local_var(fp, v); stack_push(stackval_replace(stack_pop(), *var)); break; } case STOREV: { + uint16_t level = *pc++; uint16_t v = *pc++; - json_t** var = frame_local_var(frame_current(&frame_stk), v); + frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); + json_t** var = frame_local_var(fp, v); stackval val = stack_pop(); printf("V%d = ", v); json_dumpf(val.value, stdout, JSON_ENCODE_ANY); diff --git a/c/opcode.c b/c/opcode.c index ff41f86c..87179a51 100644 --- a/c/opcode.c +++ b/c/opcode.c @@ -2,7 +2,7 @@ #define NONE 0 #define CONSTANT (OP_HAS_IMMEDIATE | OP_HAS_CONSTANT) -#define VARIABLE (OP_HAS_IMMEDIATE | OP_HAS_VARIABLE | OP_HAS_BINDING) +#define VARIABLE (OP_HAS_DOUBLE_IMMEDIATE | OP_HAS_VARIABLE | OP_HAS_BINDING) #define BRANCH (OP_HAS_IMMEDIATE | OP_HAS_BRANCH) #define CFUNC (OP_HAS_IMMEDIATE | OP_HAS_SYMBOL | OP_HAS_CFUNC) #define UFUNC (OP_HAS_IMMEDIATE | OP_HAS_UFUNC | OP_HAS_VARIABLE_LENGTH_ARGLIST) diff --git a/c/opcode.h b/c/opcode.h index 262ecb3b..87d24349 100644 --- a/c/opcode.h +++ b/c/opcode.h @@ -25,6 +25,7 @@ enum { OP_HAS_VARIABLE_LENGTH_ARGLIST = 256, OP_HAS_BLOCK = 512, OP_HAS_BINDING = 1024, + OP_HAS_DOUBLE_IMMEDIATE = 2048, }; struct opcode_description { opcode op; @@ -36,6 +37,8 @@ struct opcode_description { const struct opcode_description* opcode_describe(opcode op); static inline int opcode_length(opcode op) { - return 1 + (opcode_describe(op)->flags & OP_HAS_IMMEDIATE ? 1 : 0); + return 1 + + (opcode_describe(op)->flags & OP_HAS_IMMEDIATE ? 1 : 0) + + (opcode_describe(op)->flags & OP_HAS_DOUBLE_IMMEDIATE ? 2 : 0); } #endif diff --git a/c/testdata b/c/testdata index cc4d17bc..cefc4b04 100644 --- a/c/testdata +++ b/c/testdata @@ -140,4 +140,4 @@ def f: . + 1; def g: def g: . + 100; $$f | $$g | $$f; ($$f | $$g), $$g [[100,200][] as $x | def f: . + $x; $$f | $$f | $$f] 1 -[300.0, 600.0] \ No newline at end of file +[301.0, 601.0] From 2086e59ab16bf5c370421c967dd5b4596e170456 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Wed, 22 Aug 2012 19:05:53 +0100 Subject: [PATCH 008/284] bugfix for backtracking over RET insns, and a truly evil testcase --- c/bytecode.c | 2 +- c/compile.c | 6 +++--- c/execute.c | 29 ++++++++++++++++------------- c/forkable_stack.h | 6 +++++- c/frame_layout.h | 44 +++++++++++++++++++++++++++++--------------- c/main.c | 1 - c/opcode.c | 19 ++++++++++--------- c/opcode.h | 14 +++++++++----- c/opcode_list.h | 4 ++-- c/testdata | 11 ++++++++--- 10 files changed, 83 insertions(+), 53 deletions(-) diff --git a/c/bytecode.c b/c/bytecode.c index 08d7fff3..c85be804 100644 --- a/c/bytecode.c +++ b/c/bytecode.c @@ -35,7 +35,7 @@ void dump_operation(struct bytecode* bc, uint16_t* codeptr) { printf("%04d ", pc); const struct opcode_description* op = opcode_describe(bc->code[pc++]); printf("%s", op->name); - if (op->flags & OP_HAS_IMMEDIATE || op->flags & OP_HAS_DOUBLE_IMMEDIATE) { + if (op->length > 1) { uint16_t imm = bc->code[pc++]; if (op->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) { for (int i=0; iflags & OP_HAS_IMMEDIATE)); + assert(opcode_describe(op)->length == 1); return inst_block(inst_new(op)); } @@ -364,8 +364,8 @@ static void compile(struct bytecode* bc, block b) { } } assert(found); - } else if (opflags & OP_HAS_IMMEDIATE) { - code[pos++] = curr->imm.intval; + } else if (op->length > 1) { + assert(0 && "codegen not implemented for this operation"); } } bc->constants = constant_pool; diff --git a/c/execute.c b/c/execute.c index 5245682b..a8dfc5e7 100644 --- a/c/execute.c +++ b/c/execute.c @@ -104,6 +104,7 @@ static struct closure make_closure(struct forkable_stack* stk, frame_ptr fr, uin assert(subfn_idx < frame_self(fr)->bc->nsubfunctions); return closure_new(stk, frame_self(fr)->bc->subfunctions[subfn_idx]); } else { + // FIXME: set pc return *frame_closure_arg(fr, idx); } } @@ -116,13 +117,14 @@ json_t* jq_next() { json_t* cfunc_input[MAX_CFUNCTION_ARGS] = {0}; json_t* cfunc_output[MAX_CFUNCTION_ARGS] = {0}; - assert(!forkable_stack_empty(&frame_stk)); - uint16_t* pc = *frame_current_pc(&frame_stk); + uint16_t* pc = *frame_current_retaddr(&frame_stk); + frame_pop(&frame_stk); + + assert(!forkable_stack_empty(&frame_stk)); int backtracking = 0; while (1) { - *frame_current_pc(&frame_stk) = pc; dump_operation(frame_current_bytecode(&frame_stk), pc); uint16_t opcode = *pc++; @@ -299,7 +301,7 @@ json_t* jq_next() { return 0; } stack_restore(); - pc = *frame_current_pc(&frame_stk); + pc = *frame_current_retaddr(&frame_stk); frame_pop(&frame_stk); backtracking = 1; break; @@ -320,7 +322,7 @@ json_t* jq_next() { case YIELD: { json_t* value = stack_pop().value; - *frame_current_pc(&frame_stk) = pc; + frame_push_backtrack(&frame_stk, pc); return value; } @@ -350,9 +352,9 @@ json_t* jq_next() { case CALL_1_1: { uint16_t nclosures = *pc++; - *frame_current_pc(&frame_stk) = pc + nclosures * 2; frame_ptr new_frame = frame_push(&frame_stk, - make_closure(&frame_stk, frame_current(&frame_stk), pc)); + make_closure(&frame_stk, frame_current(&frame_stk), pc), + pc + nclosures * 2); pc += 2; frame_ptr old_frame = forkable_stack_peek_next(&frame_stk, new_frame); for (int i=0; icode; break; } case RET: { + pc = *frame_current_retaddr(&frame_stk); frame_pop(&frame_stk); - pc = *frame_current_pc(&frame_stk); break; } } @@ -375,12 +377,13 @@ json_t* jq_next() { void jq_init(struct bytecode* bc, json_t* input) { - forkable_stack_init(&data_stk, sizeof(stackval) * 100); // FIXME: lower this number, see if it breaks - forkable_stack_init(&frame_stk, 1024); // FIXME: lower this number, see if it breaks - forkable_stack_init(&fork_stk, 1024); // FIXME: lower this number, see if it breaks + forkable_stack_init(&data_stk, sizeof(stackval) * 1000); // FIXME: lower this number, see if it breaks + forkable_stack_init(&frame_stk, 10240); // FIXME: lower this number, see if it breaks + forkable_stack_init(&fork_stk, 10240); // FIXME: lower this number, see if it breaks stack_push(stackval_root(input)); - frame_push(&frame_stk, closure_new_toplevel(bc)); + frame_push(&frame_stk, closure_new_toplevel(bc), 0); + frame_push_backtrack(&frame_stk, bc->code); } void run_program(struct bytecode* bc) { diff --git a/c/forkable_stack.h b/c/forkable_stack.h index 3de9f3e0..971b4ec0 100644 --- a/c/forkable_stack.h +++ b/c/forkable_stack.h @@ -76,7 +76,11 @@ static void* forkable_stack_peek(struct forkable_stack* s) { static void* forkable_stack_peek_next(struct forkable_stack* s, void* top) { forkable_stack_check(s); struct forkable_stack_header* elem = top; - return (void*)(s->stk + elem->next); + if (elem->next < s->length) { + return (void*)(s->stk + elem->next); + } else { + return 0; + } } static void forkable_stack_pop(struct forkable_stack* s) { diff --git a/c/frame_layout.h b/c/frame_layout.h index 373c2b86..b2e590eb 100644 --- a/c/frame_layout.h +++ b/c/frame_layout.h @@ -5,12 +5,18 @@ struct closure { struct bytecode* bc; - uint16_t* pc; stack_idx env; }; +struct continuation { + struct bytecode* bc; + stack_idx env; + uint16_t* retaddr; +}; + typedef union frame_elem { FORKABLE_STACK_HEADER; + struct continuation cont; struct closure closure; json_t* jsonval; } *frame_ptr; @@ -27,8 +33,8 @@ static int frame_size(struct bytecode* bc) { return sizeof(union frame_elem) * (bc->nclosures + bc->nlocals + 2); } -static struct closure* frame_self(frame_ptr fr) { - return &fr[1].closure; +static struct continuation* frame_self(frame_ptr fr) { + return &fr[1].cont; } static struct closure* frame_closure_arg(frame_ptr fr, int closure) { @@ -46,16 +52,20 @@ static json_t** frame_local_var(frame_ptr fr, int var) { static frame_ptr frame_current(struct forkable_stack* stk) { frame_ptr fp = forkable_stack_peek(stk); - struct bytecode* bc = frame_self(fp)->bc; - assert(frame_self(fp)->pc >= bc->code && frame_self(fp)->pc < bc->code + bc->codelen); + if (forkable_stack_peek_next(stk, fp)) { + struct bytecode* bc = frame_self(forkable_stack_peek_next(stk, fp))->bc; + assert(frame_self(fp)->retaddr >= bc->code && frame_self(fp)->retaddr < bc->code + bc->codelen); + } else { + assert(frame_self(fp)->retaddr == 0); + } return fp; } static struct bytecode* frame_current_bytecode(struct forkable_stack* stk) { return frame_self(frame_current(stk))->bc; } -static uint16_t** frame_current_pc(struct forkable_stack* stk) { - return &frame_self(frame_current(stk))->pc; +static uint16_t** frame_current_retaddr(struct forkable_stack* stk) { + return &frame_self(frame_current(stk))->retaddr; } static frame_ptr frame_get_parent(struct forkable_stack* stk, frame_ptr fr) { @@ -70,26 +80,30 @@ static frame_ptr frame_get_level(struct forkable_stack* stk, frame_ptr fr, int l } static struct closure closure_new_toplevel(struct bytecode* bc) { - struct closure cl = {bc, bc->code, -1}; + struct closure cl = {bc, -1}; return cl; } + static struct closure closure_new(struct forkable_stack* stk, struct bytecode* bc) { - struct closure cl = {bc, bc->code, + struct closure cl = {bc, forkable_stack_to_idx(stk, frame_current(stk))}; return cl; } -static frame_ptr frame_push(struct forkable_stack* stk, struct closure cl) { +static frame_ptr frame_push(struct forkable_stack* stk, struct closure cl, uint16_t* retaddr) { frame_ptr fp = forkable_stack_push(stk, frame_size(cl.bc)); - *frame_self(fp) = cl; + struct continuation* cc = frame_self(fp); + cc->bc = cl.bc; + cc->env = cl.env; + cc->retaddr = retaddr; return fp; } -static frame_ptr frame_push_backtrack(struct forkable_stack* stk, uint16_t* pc) { - struct closure curr = *frame_self(frame_current(stk)); +static frame_ptr frame_push_backtrack(struct forkable_stack* stk, uint16_t* retaddr) { + struct continuation cc = *frame_self(frame_current(stk)); frame_ptr fp = forkable_stack_push(stk, sizeof(union frame_elem) * 2); - curr.pc = pc; - *frame_self(fp) = curr; + cc.retaddr = retaddr; + *frame_self(fp) = cc; return fp; } diff --git a/c/main.c b/c/main.c index f8ea2149..66984842 100644 --- a/c/main.c +++ b/c/main.c @@ -54,7 +54,6 @@ void run_tests() { json_dumpf(actual, stdout, JSON_ENCODE_ANY); printf("\n"); pass = 0; - break; } } if (pass) { diff --git a/c/opcode.c b/c/opcode.c index 87179a51..8e107236 100644 --- a/c/opcode.c +++ b/c/opcode.c @@ -1,13 +1,14 @@ #include "opcode.h" -#define NONE 0 -#define CONSTANT (OP_HAS_IMMEDIATE | OP_HAS_CONSTANT) -#define VARIABLE (OP_HAS_DOUBLE_IMMEDIATE | OP_HAS_VARIABLE | OP_HAS_BINDING) -#define BRANCH (OP_HAS_IMMEDIATE | OP_HAS_BRANCH) -#define CFUNC (OP_HAS_IMMEDIATE | OP_HAS_SYMBOL | OP_HAS_CFUNC) -#define UFUNC (OP_HAS_IMMEDIATE | OP_HAS_UFUNC | OP_HAS_VARIABLE_LENGTH_ARGLIST) -#define CLOSURE_DEFINE (OP_HAS_IMMEDIATE | OP_HAS_BLOCK | OP_IS_CALL_PSEUDO | OP_HAS_BINDING) -#define CLOSURE_REF (OP_HAS_IMMEDIATE | OP_IS_CALL_PSEUDO | OP_HAS_BINDING) +// flags, length +#define NONE 0, 1 +#define CONSTANT OP_HAS_CONSTANT, 2 +#define VARIABLE (OP_HAS_VARIABLE | OP_HAS_BINDING), 3 +#define BRANCH OP_HAS_BRANCH, 2 +#define CFUNC (OP_HAS_SYMBOL | OP_HAS_CFUNC), 2 +#define UFUNC (OP_HAS_UFUNC | OP_HAS_VARIABLE_LENGTH_ARGLIST), 2 +#define CLOSURE_DEFINE (OP_HAS_BLOCK | OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 2 +#define CLOSURE_ACCESS (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 2 #define OP(name, imm, in, out) \ {name, #name, imm, in, out}, @@ -17,7 +18,7 @@ static const struct opcode_description opcode_descriptions[] = { }; static const struct opcode_description invalid_opcode_description = { - -1, "#INVALID", 0, 0, 0 + -1, "#INVALID", 0, 0, 0, 0 }; diff --git a/c/opcode.h b/c/opcode.h index 87d24349..73948cd5 100644 --- a/c/opcode.h +++ b/c/opcode.h @@ -1,5 +1,7 @@ #ifndef OPCODE_H #define OPCODE_H +#include + typedef enum { #define OP(name, imm, in, out) name, #include "opcode_list.h" @@ -14,7 +16,6 @@ enum { }; enum { - OP_HAS_IMMEDIATE = 1, OP_HAS_CONSTANT = 2, OP_HAS_VARIABLE = 4, OP_HAS_BRANCH = 8, @@ -25,20 +26,23 @@ enum { OP_HAS_VARIABLE_LENGTH_ARGLIST = 256, OP_HAS_BLOCK = 512, OP_HAS_BINDING = 1024, - OP_HAS_DOUBLE_IMMEDIATE = 2048, }; struct opcode_description { opcode op; const char* name; + int flags; + + // length in 16-bit units + int length; + int stack_in, stack_out; }; const struct opcode_description* opcode_describe(opcode op); static inline int opcode_length(opcode op) { - return 1 + - (opcode_describe(op)->flags & OP_HAS_IMMEDIATE ? 1 : 0) + - (opcode_describe(op)->flags & OP_HAS_DOUBLE_IMMEDIATE ? 2 : 0); + return opcode_describe(op)->length; } + #endif diff --git a/c/opcode_list.h b/c/opcode_list.h index c54e1fda..497ae88a 100644 --- a/c/opcode_list.h +++ b/c/opcode_list.h @@ -20,6 +20,6 @@ OP(CALL_BUILTIN_3_1, CFUNC, 3, 1) OP(CALL_1_1, UFUNC, 1, 1) OP(RET, NONE, 1, 1) -OP(CLOSURE_PARAM, CLOSURE_REF, 0, 0) -OP(CLOSURE_REF, CLOSURE_REF, 0, 0) +OP(CLOSURE_PARAM, CLOSURE_ACCESS, 0, 0) +OP(CLOSURE_REF, CLOSURE_ACCESS, 0, 0) OP(CLOSURE_CREATE, CLOSURE_DEFINE, 0, 0) diff --git a/c/testdata b/c/testdata index cefc4b04..e22f09ce 100644 --- a/c/testdata +++ b/c/testdata @@ -138,6 +138,11 @@ def f: . + 1; def g: def g: . + 100; $$f | $$g | $$f; ($$f | $$g), $$g 106.0 105.0 -[[100,200][] as $x | def f: . + $x; $$f | $$f | $$f] -1 -[301.0, 601.0] +def f: (1000,2000); $$f +123412345 +1000 +2000 + +[[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | $$g; $$f[0] | [$$f][0][1] | $$f] +"woo, testing!" +[[110.0, 130.0], [210.0, 130.0], [110.0, 230.0], [210.0, 230.0], [120.0, 160.0], [220.0, 160.0], [120.0, 260.0], [220.0, 260.0]] From befb103a12dbc9f2a566c41cdb86b517ec4094bd Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Wed, 22 Aug 2012 19:21:35 +0100 Subject: [PATCH 009/284] Fix a revolting hack --- c/compile.c | 11 ++--------- c/opcode.c | 2 +- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/c/compile.c b/c/compile.c index 913cebca..71988c4a 100644 --- a/c/compile.c +++ b/c/compile.c @@ -312,16 +312,9 @@ static void compile(struct bytecode* bc, block b) { json_t* constant_pool = json_array(); int maxvar = -1; for (inst* curr = b.first; curr; curr = curr->next) { - if (curr->op == CLOSURE_CREATE) { - // CLOSURE_CREATE opcodes define closures for use later in the - // codestream. They generate no code. - - // FIXME: make the above true :) - code[pos++] = DUP; - code[pos++] = POP; - continue; - } const struct opcode_description* op = opcode_describe(curr->op); + if (op->length == 0) + continue; code[pos++] = curr->op; int opflags = op->flags; assert(!(op->flags & OP_IS_CALL_PSEUDO)); diff --git a/c/opcode.c b/c/opcode.c index 8e107236..5a7bfb2c 100644 --- a/c/opcode.c +++ b/c/opcode.c @@ -7,7 +7,7 @@ #define BRANCH OP_HAS_BRANCH, 2 #define CFUNC (OP_HAS_SYMBOL | OP_HAS_CFUNC), 2 #define UFUNC (OP_HAS_UFUNC | OP_HAS_VARIABLE_LENGTH_ARGLIST), 2 -#define CLOSURE_DEFINE (OP_HAS_BLOCK | OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 2 +#define CLOSURE_DEFINE (OP_HAS_BLOCK | OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0 #define CLOSURE_ACCESS (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 2 #define OP(name, imm, in, out) \ From a847d2250f9ac16847414ddc2fed796a9b989f27 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sun, 26 Aug 2012 14:25:56 +0100 Subject: [PATCH 010/284] 2nd order functions --- c/bytecode.c | 3 +++ c/compile.c | 62 +++++++++++++++++++++++++++++++++++++++++-------- c/execute.c | 1 + c/opcode.c | 5 ++-- c/opcode_list.h | 6 ++--- c/parser.y | 13 +++++++++++ c/testdata | 7 ++++++ 7 files changed, 82 insertions(+), 15 deletions(-) diff --git a/c/bytecode.c b/c/bytecode.c index c85be804..ef585bd7 100644 --- a/c/bytecode.c +++ b/c/bytecode.c @@ -13,6 +13,9 @@ static int bytecode_operation_length(uint16_t* codeptr) { } void dump_disassembly(int indent, struct bytecode* bc) { + if (bc->nclosures > 0) { + printf("%*s[params: %d]\n", indent, "", bc->nclosures); + } dump_code(indent, bc); for (int i=0; insubfunctions; i++) { printf("%*ssubfn[%d]:\n", indent, "", i); diff --git a/c/compile.c b/c/compile.c index 71988c4a..d2b9cee7 100644 --- a/c/compile.c +++ b/c/compile.c @@ -59,6 +59,24 @@ static block inst_block(inst* i) { return b; } +static int block_is_single(block b) { + return b.first && b.first == b.last; +} + +static inst* block_take(block* b) { + if (b->first == 0) return 0; + inst* i = b->first; + if (i->next) { + i->next->prev = 0; + b->first = i->next; + i->next = 0; + } else { + b->first = 0; + b->last = 0; + } + return i; +} + block gen_noop() { block b = {0,0}; return b; @@ -92,8 +110,7 @@ block gen_op_targetlater(opcode op) { return inst_block(i); } void inst_set_target(block b, block target) { - assert(b.first); - assert(b.first == b.last); + assert(block_is_single(b)); assert(opcode_describe(b.first->op)->flags & OP_HAS_BRANCH); assert(target.last); b.first->imm.target = target.last; @@ -107,9 +124,7 @@ block gen_op_var_unbound(opcode op, const char* name) { } block gen_op_var_bound(opcode op, block binder) { - assert(opcode_describe(op)->flags & OP_HAS_VARIABLE); - assert(binder.first); - assert(binder.first == binder.last); + assert(block_is_single(binder)); block b = gen_op_var_unbound(op, binder.first->symbol); b.first->bound_by = binder.first; return b; @@ -138,18 +153,38 @@ block gen_op_block_unbound(opcode op, const char* name) { return inst_block(i); } +block gen_op_block_bound(opcode op, block binder) { + assert(block_is_single(binder)); + block b = gen_op_block_unbound(op, binder.first->symbol); + b.first->bound_by = binder.first; + return b; +} block gen_op_call(opcode op, block arglist) { assert(opcode_describe(op)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST); inst* i = inst_new(op); + block prelude = gen_noop(); + block call = inst_block(i); int nargs = 0; - for (inst* curr = arglist.first; curr; curr = curr->next) { + inst* curr = 0; + while ((curr = block_take(&arglist))) { assert(opcode_describe(curr->op)->flags & OP_IS_CALL_PSEUDO); + block bcurr = inst_block(curr); + switch (curr->op) { + default: assert(0 && "Unknown type of parameter"); break; + case CLOSURE_REF: + block_append(&call, bcurr); + break; + case CLOSURE_CREATE: + block_append(&prelude, bcurr); + block_append(&call, gen_op_block_bound(CLOSURE_REF, bcurr)); + break; + } nargs++; } assert(nargs < 100); //FIXME i->imm.intval = nargs; - return block_join(inst_block(i), arglist); + return block_join(prelude, call); } static void inst_join(inst* a, inst* b) { @@ -178,8 +213,7 @@ block block_join(block a, block b) { } static void block_bind_subblock(block binder, block body, int bindflags) { - assert(binder.first); - assert(binder.first == binder.last); + assert(block_is_single(binder)); assert((opcode_describe(binder.first->op)->flags & bindflags) == bindflags); assert(binder.first->symbol); assert(binder.first->bound_by == 0 || binder.first->bound_by == binder.first); @@ -194,6 +228,7 @@ static void block_bind_subblock(block binder, block body, int bindflags) { i->bound_by = binder.first; } if (flags & OP_HAS_BLOCK) { + // binding recurses into closures block_bind_subblock(binder, i->subfn, bindflags); } } @@ -272,6 +307,7 @@ static void compile(struct bytecode* bc, block b) { int pos = 0; int var_frame_idx = 0; bc->nsubfunctions = 0; + bc->nclosures = 0; for (inst* curr = b.first; curr; curr = curr->next) { if (!curr->next) assert(curr == b.last); pos += opcode_length(curr->op); @@ -290,6 +326,10 @@ static void compile(struct bytecode* bc, block b) { assert(curr->bound_by == curr); curr->imm.intval = bc->nsubfunctions++; } + if (curr->op == CLOSURE_PARAM) { + assert(curr->bound_by == curr); + curr->imm.intval = bc->nclosures++; + } } if (bc->nsubfunctions) { bc->subfunctions = malloc(sizeof(struct bytecode*) * bc->nsubfunctions); @@ -331,6 +371,9 @@ static void compile(struct bytecode* bc, block b) { case CLOSURE_CREATE: code[pos++] = curr->bound_by->imm.intval | ARG_NEWCLOSURE; break; + case CLOSURE_PARAM: + code[pos++] = curr->bound_by->imm.intval; + break; } } } else if (opflags & OP_HAS_CONSTANT) { @@ -363,7 +406,6 @@ static void compile(struct bytecode* bc, block b) { } bc->constants = constant_pool; bc->nlocals = maxvar + 2; // FIXME: frames of size zero? - bc->nclosures = 0; } struct bytecode* block_compile(struct symbol_table* syms, block b) { diff --git a/c/execute.c b/c/execute.c index a8dfc5e7..9d952d6b 100644 --- a/c/execute.c +++ b/c/execute.c @@ -357,6 +357,7 @@ json_t* jq_next() { pc + nclosures * 2); pc += 2; frame_ptr old_frame = forkable_stack_peek_next(&frame_stk, new_frame); + assert(nclosures - 1 == frame_self(new_frame)->bc->nclosures); for (int i=0; i Date: Mon, 27 Aug 2012 10:11:55 +0100 Subject: [PATCH 011/284] first pass at assignment --- c/compile.c | 19 +++++++++++++++++++ c/compile.h | 1 + c/execute.c | 44 +++++++++++++++++++++++++++++++++----------- c/jv.h | 41 +++++++++++++++++++++++++++++++++++++++++ c/lexer.l | 1 + c/opcode_list.h | 3 +++ c/parser.y | 18 ++++++++++++++++++ c/testdata | 1 + 8 files changed, 117 insertions(+), 11 deletions(-) create mode 100644 c/jv.h diff --git a/c/compile.c b/c/compile.c index d2b9cee7..93f71888 100644 --- a/c/compile.c +++ b/c/compile.c @@ -288,6 +288,25 @@ block gen_collect(block expr) { return c; } +block gen_assign(block expr) { + block c = gen_noop(); + block_append(&c, gen_op_simple(DUP)); + block result_var = block_bind(gen_op_var_unbound(STOREV, "result"), + gen_noop(), OP_HAS_VARIABLE); + block_append(&c, result_var); + + block loop = gen_noop(); + block_append(&loop, gen_op_simple(DUP)); + block_append(&loop, expr); + block_append(&loop, gen_op_var_bound(ASSIGN, result_var)); + block_append(&loop, gen_op_simple(BACKTRACK)); + + block_append(&c, gen_op_target(FORK, loop)); + block_append(&c, loop); + block_append(&c, gen_op_var_bound(LOADV, result_var)); + return c; +} + block gen_else(block a, block b) { assert(0); } diff --git a/c/compile.h b/c/compile.h index d72ddcef..2ce02c0e 100644 --- a/c/compile.h +++ b/c/compile.h @@ -25,6 +25,7 @@ block gen_op_symbol(opcode op, const char* name); block gen_subexp(block a); block gen_both(block a, block b); block gen_collect(block expr); +block gen_assign(block expr); block gen_else(block a, block b); diff --git a/c/execute.c b/c/execute.c index 9d952d6b..f9e2570c 100644 --- a/c/execute.c +++ b/c/execute.c @@ -12,6 +12,8 @@ #include "forkable_stack.h" #include "frame_layout.h" +#include "jv.h" + typedef struct { json_t* value; @@ -108,6 +110,8 @@ static struct closure make_closure(struct forkable_stack* stk, frame_ptr fr, uin return *frame_closure_arg(fr, idx); } } + + #define stack_push stk_push #define stack_pop stk_pop @@ -245,20 +249,37 @@ json_t* jq_next() { } #endif + case ASSIGN_DBG: { + stackval replacement = stack_pop(); + stackval path_end = stack_pop(); + stackval path_start = stack_pop(); + json_t* obj = jv_insert(path_start.value, replacement.value, pathbuf + path_start.pathidx, path_end.pathidx - path_start.pathidx); + stack_push(stackval_replace(path_start, obj)); + break; + } + + case ASSIGN: { + stackval replacement = stack_pop(); + stackval path_end = stack_pop(); + stackval path_start = stack_pop(); + + uint16_t level = *pc++; + uint16_t v = *pc++; + frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); + json_t** var = frame_local_var(fp, v); + *var = jv_insert(*var, replacement.value, pathbuf + path_start.pathidx, path_end.pathidx - path_start.pathidx); + break; + } + case INDEX: { stackval t = stack_pop(); json_t* k = stack_pop().value; - stackval v; - if (json_is_string(k)) { - v.value = json_object_get(t.value, json_string_value(k)); - } else if (json_is_integer(k)) { - v.value = json_array_get(t.value, json_integer_value(k)); - } else { - assert(0 && "key neither string nor int"); - } - if (v.value) { - v.pathidx = path_push(t, k); - stack_push(v); + json_t* v = jv_lookup(t.value, k); + if (v) { + stackval sv; + sv.value = v; + sv.pathidx = path_push(t, k); + stack_push(sv); } else { assert(0 && "bad lookup"); } @@ -314,6 +335,7 @@ json_t* jq_next() { pc++; // skip offset this time break; } + case ON_BACKTRACK(FORK): { uint16_t offset = *pc++; pc += offset; diff --git a/c/jv.h b/c/jv.h new file mode 100644 index 00000000..fc964fa9 --- /dev/null +++ b/c/jv.h @@ -0,0 +1,41 @@ +#ifndef JV_H +#define JV_H + +#include + +static json_t* jv_lookup(json_t* t, json_t* k) { + json_t* v; + if (json_is_object(t) && json_is_string(k)) { + v = json_object_get(t, json_string_value(k)); + } else if (json_is_array(t) && json_is_number(k)) { + v = json_array_get(t, json_integer_value(k)); + } else { + assert(0&&"bad lookup"); + } + if (v) + return v; + else + return json_null(); +} + +static json_t* jv_modify(json_t* t, json_t* k, json_t* v) { + t = json_copy(t); + if (json_is_object(t) && json_is_string(k)) { + json_object_set(t, json_string_value(k), v); + } else if (json_is_array(t) && json_is_number(k)) { + json_array_set(t, json_integer_value(k), v); + } else { + assert(0 && "bad mod"); + } + return t; +} + +static json_t* jv_insert(json_t* root, json_t* value, json_t** path, int pathlen) { + if (pathlen == 0) { + return value; + } + return jv_modify(root, *path, jv_insert(jv_lookup(root, *path), value, path+1, pathlen-1)); +} + + +#endif diff --git a/c/lexer.l b/c/lexer.l index abf33263..e4ffafce 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -12,6 +12,7 @@ "==" { return EQ; } "as" { return AS; } "def" { return DEF; } +"|=" { return SETPIPE; } "."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];} [[:digit:]]+ { yylval->num = atoi(yytext); return NUMBER;} diff --git a/c/opcode_list.h b/c/opcode_list.h index 1d6d2773..dde07226 100644 --- a/c/opcode_list.h +++ b/c/opcode_list.h @@ -14,6 +14,9 @@ OP(BACKTRACK, NONE, 0, 0) OP(APPEND, NONE, 2, 1) OP(INSERT, NONE, 4, 2) +OP(ASSIGN_DBG, NONE, 3, 1) +OP(ASSIGN, VARIABLE, 3, 0) + OP(CALL_BUILTIN_1_1, CFUNC, 1, 1) OP(CALL_BUILTIN_3_1, CFUNC, 3, 1) diff --git a/c/parser.y b/c/parser.y index ebc90a32..31c70865 100644 --- a/c/parser.y +++ b/c/parser.y @@ -28,6 +28,8 @@ %token EQ "==" %token AS "as" %token DEF "def" +%token SETPIPE "|=" +%nonassoc '=' SETPIPE %nonassoc EQ %left '+' @@ -76,6 +78,22 @@ Term "as" '$' IDENT '|' Exp { block_append(&$$, block_bind(gen_op_var_unbound(STOREV, $4), $6, OP_HAS_VARIABLE)); } | +Exp '=' Exp { + block assign = gen_op_simple(DUP); + block_append(&assign, $3); + block_append(&assign, gen_op_simple(SWAP)); + block_append(&assign, $1); + block_append(&assign, gen_op_simple(SWAP)); + $$ = gen_assign(assign); +} | + +Exp "|=" Exp { + block assign = $1; + block_append(&assign, gen_op_simple(DUP)); + block_append(&assign, $3); + $$ = gen_assign(assign); +} | + Exp '|' Exp { $$ = block_join($1, $3); } | diff --git a/c/testdata b/c/testdata index f2bd4ee3..1d8420d6 100644 --- a/c/testdata +++ b/c/testdata @@ -153,3 +153,4 @@ def f(x): $$x | $$x; $$f([.], . + [42]) [[1,2,3],42] [[1,2,3,42]] [1,2,3,42,42] + From dc6cf2fb58b8ec2d27fcbdb564295547c183e09d Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 27 Aug 2012 11:19:42 +0100 Subject: [PATCH 012/284] Remove syntax distinction between builtin and user calls --- c/compile.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- c/compile.h | 5 ++++- c/execute.c | 6 ++++++ c/main.c | 4 ++-- c/opcode.c | 3 ++- c/opcode_list.h | 1 + c/parser.y | 15 ++++++--------- c/testdata | 8 ++++---- 8 files changed, 68 insertions(+), 19 deletions(-) diff --git a/c/compile.c b/c/compile.c index 93f71888..f9f738d8 100644 --- a/c/compile.c +++ b/c/compile.c @@ -14,6 +14,7 @@ struct inst { uint16_t intval; struct inst* target; json_t* constant; + struct cfunction* cfunc; } imm; // Binding @@ -311,6 +312,16 @@ block gen_else(block a, block b) { assert(0); } +block gen_cbinding(struct symbol_table* t, block code) { + for (int cfunc=0; cfuncncfunctions; cfunc++) { + inst* i = inst_new(CLOSURE_CREATE_C); + i->imm.cfunc = &t->cfunctions[cfunc]; + i->symbol = strdup(i->imm.cfunc->name); + code = block_bind(inst_block(i), code, OP_IS_CALL_PSEUDO); + } + return code; +} + static uint16_t nesting_level(struct bytecode* bc, inst* target) { uint16_t level = 0; assert(bc && target->compiled); @@ -322,6 +333,16 @@ static uint16_t nesting_level(struct bytecode* bc, inst* target) { return level; } +static int count_cfunctions(block b) { + int n = 0; + for (inst* i = b.first; i; i = i->next) { + if (i->op == CLOSURE_CREATE_C) n++; + if (opcode_describe(i->op)->flags & OP_HAS_BLOCK) + n += count_cfunctions(i->subfn); + } + return n; +} + static void compile(struct bytecode* bc, block b) { int pos = 0; int var_frame_idx = 0; @@ -349,6 +370,12 @@ static void compile(struct bytecode* bc, block b) { assert(curr->bound_by == curr); curr->imm.intval = bc->nclosures++; } + if (curr->op == CLOSURE_CREATE_C) { + assert(curr->bound_by == curr); + int idx = bc->globals->ncfunctions++; + bc->globals->cfunctions[idx] = *curr->imm.cfunc; + curr->imm.intval = idx; + } } if (bc->nsubfunctions) { bc->subfunctions = malloc(sizeof(struct bytecode*) * bc->nsubfunctions); @@ -374,6 +401,7 @@ static void compile(struct bytecode* bc, block b) { const struct opcode_description* op = opcode_describe(curr->op); if (op->length == 0) continue; + uint16_t* opcode_rewrite = &code[pos]; code[pos++] = curr->op; int opflags = op->flags; assert(!(op->flags & OP_IS_CALL_PSEUDO)); @@ -381,6 +409,7 @@ static void compile(struct bytecode* bc, block b) { int nargs = curr->imm.intval; assert(nargs > 0); code[pos++] = (uint16_t)nargs; + int desired_params; for (int i=0; inext; assert(curr && opcode_describe(curr->op)->flags & OP_IS_CALL_PSEUDO); @@ -389,12 +418,20 @@ static void compile(struct bytecode* bc, block b) { default: assert(0 && "Unknown type of argument"); case CLOSURE_CREATE: code[pos++] = curr->bound_by->imm.intval | ARG_NEWCLOSURE; + if (i == 0) desired_params = bc->subfunctions[curr->bound_by->imm.intval]->nclosures; break; case CLOSURE_PARAM: code[pos++] = curr->bound_by->imm.intval; + if (i == 0) desired_params = 0; + break; + case CLOSURE_CREATE_C: + code[pos++] = curr->bound_by->imm.intval; + *opcode_rewrite = bc->globals->cfunctions[curr->bound_by->imm.intval].callop; + if (i == 0) desired_params = 0; break; } } + assert(nargs - 1 == desired_params); } else if (opflags & OP_HAS_CONSTANT) { code[pos++] = json_array_size(constant_pool); json_array_append(constant_pool, curr->imm.constant); @@ -427,11 +464,15 @@ static void compile(struct bytecode* bc, block b) { bc->nlocals = maxvar + 2; // FIXME: frames of size zero? } -struct bytecode* block_compile(struct symbol_table* syms, block b) { +struct bytecode* block_compile(block b) { struct bytecode* bc = malloc(sizeof(struct bytecode)); bc->parent = 0; - bc->globals = syms; + bc->globals = malloc(sizeof(struct symbol_table)); + int ncfunc = count_cfunctions(b); + bc->globals->ncfunctions = 0; + bc->globals->cfunctions = malloc(sizeof(struct cfunction) * ncfunc); compile(bc, b); + assert(bc->globals->ncfunctions == ncfunc); return bc; } diff --git a/c/compile.h b/c/compile.h index 2ce02c0e..4c0a3a17 100644 --- a/c/compile.h +++ b/c/compile.h @@ -28,11 +28,14 @@ block gen_collect(block expr); block gen_assign(block expr); block gen_else(block a, block b); +block gen_cbinding(struct symbol_table* functions, block b); void block_append(block* b, block b2); block block_join(block a, block b); block block_bind(block binder, block body, int bindflags); -struct bytecode* block_compile(struct symbol_table*, block); +struct bytecode* block_compile(block); void block_free(block); + + diff --git a/c/execute.c b/c/execute.c index f9e2570c..75aaec09 100644 --- a/c/execute.c +++ b/c/execute.c @@ -349,6 +349,9 @@ json_t* jq_next() { } case CALL_BUILTIN_1_1: { + assert(*pc == 1); // no closure args allowed + pc++; // skip nclosures + pc++; // skip level stackval top = stack_pop(); cfunc_input[0] = top.value; struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++]; @@ -359,6 +362,9 @@ json_t* jq_next() { } case CALL_BUILTIN_3_1: { + assert(*pc == 1); // no closure args allowed + pc++; // skip nclosures + pc++; // skip level stackval top = stack_pop(); json_t* a = stack_pop().value; json_t* b = stack_pop().value; diff --git a/c/main.c b/c/main.c index 66984842..c03b5a99 100644 --- a/c/main.c +++ b/c/main.c @@ -30,7 +30,7 @@ void run_tests() { block program = compile(buf); block_append(&program, gen_op_simple(YIELD)); block_append(&program, gen_op_simple(BACKTRACK)); - struct bytecode* bc = block_compile(&builtins, program); + struct bytecode* bc = block_compile(gen_cbinding(&builtins, program)); block_free(program); printf("Disassembly:\n"); dump_disassembly(2, bc); @@ -76,7 +76,7 @@ int main(int argc, char* argv[]) { if (argc == 1) { run_tests(); return 0; } block blk = compile(argv[1]); block_append(&blk, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK))); - struct bytecode* bc = block_compile(&builtins, blk); + struct bytecode* bc = block_compile(gen_cbinding(&builtins, blk)); block_free(blk); dump_disassembly(0, bc); printf("\n"); diff --git a/c/opcode.c b/c/opcode.c index 62624c92..bc259c22 100644 --- a/c/opcode.c +++ b/c/opcode.c @@ -5,10 +5,11 @@ #define CONSTANT OP_HAS_CONSTANT, 2 #define VARIABLE (OP_HAS_VARIABLE | OP_HAS_BINDING), 3 #define BRANCH OP_HAS_BRANCH, 2 -#define CFUNC (OP_HAS_SYMBOL | OP_HAS_CFUNC), 2 +#define CFUNC (OP_HAS_SYMBOL | OP_HAS_CFUNC | OP_HAS_VARIABLE_LENGTH_ARGLIST), 2 #define UFUNC (OP_HAS_UFUNC | OP_HAS_VARIABLE_LENGTH_ARGLIST), 2 #define CLOSURE_PARAM_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0 #define CLOSURE_CREATE_IMM (OP_HAS_BLOCK | OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0 +#define CLOSURE_CREATE_C_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0 #define CLOSURE_REF_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 2 #define OP(name, imm, in, out) \ diff --git a/c/opcode_list.h b/c/opcode_list.h index dde07226..268025e8 100644 --- a/c/opcode_list.h +++ b/c/opcode_list.h @@ -26,3 +26,4 @@ OP(RET, NONE, 1, 1) OP(CLOSURE_PARAM, CLOSURE_PARAM_IMM, 0, 0) OP(CLOSURE_REF, CLOSURE_REF_IMM, 0, 0) OP(CLOSURE_CREATE, CLOSURE_CREATE_IMM, 0, 0) +OP(CLOSURE_CREATE_C, CLOSURE_CREATE_C_IMM, 0, 0) diff --git a/c/parser.y b/c/parser.y index 31c70865..5ec03892 100644 --- a/c/parser.y +++ b/c/parser.y @@ -106,7 +106,7 @@ Exp '+' Exp { $$ = gen_noop(); block_append(&$$, gen_subexp($1)); block_append(&$$, gen_subexp($3)); - block_append(&$$, gen_op_symbol(CALL_BUILTIN_3_1, "_plus")); + block_append(&$$, gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, "_plus"))); } | Term { @@ -158,21 +158,18 @@ NUMBER { block_append(&$$, $2); block_append(&$$, gen_op_simple(POP)); } | -IDENT { - $$ = gen_op_symbol(CALL_BUILTIN_1_1, $1); -} | '$' IDENT { $$ = gen_op_var_unbound(LOADV, $2); } | -'$' '$' IDENT { - $$ = gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, $3)); +IDENT { + $$ = gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, $1)); } | -'$' '$' IDENT '(' Exp ')' { +IDENT '(' Exp ')' { $$ = gen_op_call(CALL_1_1, - block_join(gen_op_block_unbound(CLOSURE_REF, $3), + block_join(gen_op_block_unbound(CLOSURE_REF, $1), block_bind(gen_op_block_defn(CLOSURE_CREATE, "lambda", - block_join($5, gen_op_simple(RET))), + block_join($3, gen_op_simple(RET))), gen_noop(), OP_IS_CALL_PSEUDO))); } diff --git a/c/testdata b/c/testdata index 1d8420d6..6e40b9ae 100644 --- a/c/testdata +++ b/c/testdata @@ -133,21 +133,21 @@ null # Oh god. # -def f: . + 1; def g: def g: . + 100; $$f | $$g | $$f; ($$f | $$g), $$g +def f: . + 1; def g: def g: . + 100; f | g | f; (f | g), g 3.0 106.0 105.0 -def f: (1000,2000); $$f +def f: (1000,2000); f 123412345 1000 2000 -[[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | $$g; $$f[0] | [$$f][0][1] | $$f] +[[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | g; f[0] | [f][0][1] | f] "woo, testing!" [[110.0, 130.0], [210.0, 130.0], [110.0, 230.0], [210.0, 230.0], [120.0, 160.0], [220.0, 160.0], [120.0, 260.0], [220.0, 260.0]] -def f(x): $$x | $$x; $$f([.], . + [42]) +def f(x): x | x; f([.], . + [42]) [1,2,3] [[[1,2,3]]] [[1,2,3],42] From 463b175cdbe29f2741478b69646b65647278f46f Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 28 Aug 2012 18:09:43 +0100 Subject: [PATCH 013/284] Reference-counted copy-on-write JSON library. Comes with tests and, presumably, bugs. --- c/Makefile | 12 +- c/jv.c | 764 +++++++++++++++++++++++++++++++++++++++++++++++++++ c/jv.h | 100 +++++++ c/jv_print.c | 45 +++ c/jvtest.c | 135 +++++++++ 5 files changed, 1055 insertions(+), 1 deletion(-) create mode 100644 c/jv.c create mode 100644 c/jv_print.c create mode 100644 c/jvtest.c diff --git a/c/Makefile b/c/Makefile index 01c3b540..b77971da 100644 --- a/c/Makefile +++ b/c/Makefile @@ -1,4 +1,4 @@ -CC=gcc -Wall -std=gnu99 -ggdb +CC=gcc -Wall -std=gnu99 -ggdb -Wno-unused-function .PHONY: all clean all: parsertest @@ -19,3 +19,13 @@ parser.tab.h: parser.tab.c parsertest: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c $(CC) -o $@ $^ -ljansson + +jvtest: jvtest.c jv.c jv_print.c + $(CC) -o $@ $^ -ljansson + +test: jvtest + valgrind --error-exitcode=1 -q --leak-check=full ./jvtest + +jsparse: jsparse.l jv.c + flex -o jsparse.c jsparse.l + gcc -o jsparse jsparse.c -ljansson \ No newline at end of file diff --git a/c/jv.c b/c/jv.c new file mode 100644 index 00000000..09b600d8 --- /dev/null +++ b/c/jv.c @@ -0,0 +1,764 @@ +#include +#include +#include +#include +#include + +#include "jv.h" + +/* + * Internal refcounting helpers + */ + +static void jvp_refcnt_init(jv_complex* c) { + c->ptr->count = 1; +} + +static void jvp_refcnt_inc(jv_complex* c) { + c->ptr->count++; +} + +static int jvp_refcnt_dec(jv_complex* c) { + c->ptr->count--; + return c->ptr->count == 0; +} + +static int jvp_refcnt_unshared(jv_complex* c) { + assert(c->ptr->count > 0); + return c->ptr->count == 1; +} + +/* + * Simple values (true, false, null) + */ + +jv_kind jv_get_kind(jv x) { + return x.kind; +} + +static const jv JV_NULL = {JV_KIND_NULL, {0}}; +static const jv JV_FALSE = {JV_KIND_FALSE, {0}}; +static const jv JV_TRUE = {JV_KIND_TRUE, {0}}; + +jv jv_true() { + return JV_TRUE; +} + +jv jv_false() { + return JV_FALSE; +} + +jv jv_null() { + return JV_NULL; +} + +/* + * Numbers + */ + +jv jv_number(double x) { + jv j; + j.kind = JV_KIND_NUMBER; + j.val.number = x; + return j; +} + +double jv_number_value(jv j) { + assert(jv_get_kind(j) == JV_KIND_NUMBER); + return j.val.number; +} + + +/* + * Arrays (internal helpers) + */ + +#define ARRAY_SIZE_ROUND_UP(n) (((n)*3)/2) + +static int imax(int a, int b) { + if (a>b) return a; + else return b; +} + +//FIXME signed vs unsigned +typedef struct { + jv_refcnt refcnt; + int length, alloc_length; + jv elements[]; +} jvp_array; + +static jvp_array* jvp_array_ptr(jv_complex* a) { + return (jvp_array*)a->ptr; +} + +static jvp_array* jvp_array_alloc(unsigned size) { + jvp_array* a = malloc(sizeof(jvp_array) + sizeof(jv) * size); + a->refcnt.count = 1; + a->length = 0; + a->alloc_length = size; + return a; +} + +static jv_complex jvp_array_new(unsigned size) { + jv_complex r = {&jvp_array_alloc(size)->refcnt, {0, 0}}; + return r; +} + +static void jvp_array_free(jv_complex* a) { + if (jvp_refcnt_dec(a)) { + jvp_array* array = jvp_array_ptr(a); + for (int i=0; ilength; i++) { + jv_free(array->elements[i]); + } + free(array); + } +} + +static int jvp_array_length(jv_complex* a) { + return a->i[1] - a->i[0]; +} + +static jv* jvp_array_read(jv_complex* a, int i) { + assert(i >= 0 && i < jvp_array_length(a)); + jvp_array* array = jvp_array_ptr(a); + assert(i + a->i[0] < array->length); + return &array->elements[i + a->i[0]]; +} + +static jv* jvp_array_write(jv_complex* a, int i) { + assert(i >= 0); + jvp_array* array = jvp_array_ptr(a); + + int pos = i + a->i[0]; + if (pos < array->alloc_length) { + // maybe we can update it in-place + // FIXME: this "optimisation" can cause circular references + #if 0 + int can_write_past_end = + array->length <= pos && /* the end of this array has never been used */ + a->i[1] == array->length; /* the current slice sees the end of the array */ + #endif + int can_write_past_end = 0; + if (can_write_past_end || jvp_refcnt_unshared(a)) { + // extend the array + for (int j = array->length; j <= pos; j++) { + array->elements[j] = JV_NULL; + } + array->length = imax(pos + 1, array->length); + a->i[1] = imax(pos + 1, array->length); + return &array->elements[pos]; + } + } + + + int new_length = imax(i + 1, jvp_array_length(a)); + jvp_array* new_array = jvp_array_alloc(ARRAY_SIZE_ROUND_UP(new_length)); + int j; + for (j = 0; j < jvp_array_length(a); j++) { + new_array->elements[j] = jv_copy(array->elements[j + a->i[0]]); + } + for (; j < new_length; j++) { + new_array->elements[j] = JV_NULL; + } + new_array->length = new_length; + jvp_array_free(a); + a->ptr = &new_array->refcnt; + a->i[0] = 0; + a->i[1] = new_length; + return &new_array->elements[i]; +} + +static int jvp_array_equal(jv_complex* a, jv_complex* b) { + if (jvp_array_length(a) != jvp_array_length(b)) + return 0; + if (jvp_array_ptr(a) == jvp_array_ptr(b) && + a->i[0] == b->i[0]) + return 1; + for (int i=0; ii[1] + end < array->length); + jv_complex slice = *a; + slice.i[0] += start; + slice.i[1] = slice.i[0] + (end - start); + return slice; +} + +/* + * Arrays (public interface) + */ + +jv jv_array_sized(int n) { + jv j; + j.kind = JV_KIND_ARRAY; + j.val.complex = jvp_array_new(n); + return j; +} + +jv jv_array() { + return jv_array_sized(16); +} + +int jv_array_length(jv j) { + assert(jv_get_kind(j) == JV_KIND_ARRAY); + int len = jvp_array_length(&j.val.complex); + jv_free(j); + return len; +} + +jv jv_array_get(jv j, int idx) { + assert(jv_get_kind(j) == JV_KIND_ARRAY); + jv val = jv_copy(*jvp_array_read(&j.val.complex, idx)); + jv_free(j); + return val; +} + +jv jv_array_set(jv j, int idx, jv val) { + assert(jv_get_kind(j) == JV_KIND_ARRAY); + // copy/free of val,j coalesced + *jvp_array_write(&j.val.complex, idx) = val; + return j; +} + +jv jv_array_append(jv j, jv val) { + // copy/free of val,j coalesced + return jv_array_set(j, jv_array_length(jv_copy(j)), val); +} + +jv jv_array_concat(jv a, jv b) { + assert(jv_get_kind(a) == JV_KIND_ARRAY); + assert(jv_get_kind(b) == JV_KIND_ARRAY); + + // FIXME: could be much faster + for (int i=0; iptr; +} + +static jvp_string* jvp_string_alloc(uint32_t size) { + jvp_string* s = malloc(sizeof(jvp_string) + size + 1); + s->refcnt.count = 1; + s->length_hashed = size << 1; + return s; +} + +static jv_complex jvp_string_new(char* data, uint32_t length) { + jvp_string* s = jvp_string_alloc(length); + memcpy(s->data, data, length); + s->data[length] = 0; + jv_complex r = {&s->refcnt, {0,0}}; + return r; +} + +static void jvp_string_free(jv_complex* s) { + if (jvp_refcnt_dec(s)) { + jvp_string* str = jvp_string_ptr(s); + free(str); + } +} + +static void jvp_string_free_p(jvp_string* s) { + jv_complex p = {&s->refcnt,{0,0}}; + jvp_string_free(&p); +} + +static jvp_string* jvp_string_copy_p(jvp_string* s) { + jv_complex p = {&s->refcnt,{0,0}}; + jvp_refcnt_inc(&p); + return s; +} + +static uint32_t jvp_string_length(jvp_string* s) { + return s->length_hashed >> 1; +} + +static const uint32_t HASH_SEED = 0x432A9843; + +static uint32_t rotl32 (uint32_t x, int8_t r){ + return (x << r) | (x >> (32 - r)); +} + +static uint32_t jvp_string_hash(jvp_string* str) { + if (str->length_hashed & 1) + return str->hash; + + /* The following is based on MurmurHash3. + MurmurHash3 was written by Austin Appleby, and is placed + in the public domain. */ + + const uint8_t* data = (const uint8_t*)str->data; + int len = (int)jvp_string_length(str); + const int nblocks = len / 4; + + uint32_t h1 = HASH_SEED; + + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; + const uint32_t* blocks = (const uint32_t *)(data + nblocks*4); + + for(int i = -nblocks; i; i++) { + uint32_t k1 = blocks[i]; //FIXME: endianness/alignment + + k1 *= c1; + k1 = rotl32(k1,15); + k1 *= c2; + + h1 ^= k1; + h1 = rotl32(h1,13); + h1 = h1*5+0xe6546b64; + } + + const uint8_t* tail = (const uint8_t*)(data + nblocks*4); + + uint32_t k1 = 0; + + switch(len & 3) { + case 3: k1 ^= tail[2] << 16; + case 2: k1 ^= tail[1] << 8; + case 1: k1 ^= tail[0]; + k1 *= c1; k1 = rotl32(k1,15); k1 *= c2; h1 ^= k1; + } + + h1 ^= len; + + h1 ^= h1 >> 16; + h1 *= 0x85ebca6b; + h1 ^= h1 >> 13; + h1 *= 0xc2b2ae35; + h1 ^= h1 >> 16; + + str->length_hashed |= 1; + str->hash = h1; + + return h1; +} + +static int jvp_string_equal_hashed(jvp_string* a, jvp_string* b) { + assert(a->length_hashed & 1); + assert(b->length_hashed & 1); + if (a == b) return 1; + if (a->hash != b->hash) return 0; + if (a->length_hashed != b->length_hashed) return 0; + return memcmp(a->data, b->data, jvp_string_length(a)) == 0; +} + +static int jvp_string_equal(jv_complex* a, jv_complex* b) { + jvp_string* stra = jvp_string_ptr(a); + jvp_string* strb = jvp_string_ptr(b); + if (jvp_string_length(stra) != jvp_string_length(strb)) return 0; + return memcmp(stra->data, strb->data, jvp_string_length(stra)) == 0; +} + +/* + * Strings (public API) + */ + +jv jv_string_sized(char* str, int len) { + jv j; + j.kind = JV_KIND_STRING; + j.val.complex = jvp_string_new(str, len); + return j; +} + +jv jv_string(char* str) { + return jv_string_sized(str, strlen(str)); +} + +int jv_string_length(jv j) { + assert(jv_get_kind(j) == JV_KIND_STRING); + int r = jvp_string_length(jvp_string_ptr(&j.val.complex)); + jv_free(j); + return r; +} + +uint32_t jv_string_hash(jv j) { + assert(jv_get_kind(j) == JV_KIND_STRING); + uint32_t hash = jvp_string_hash(jvp_string_ptr(&j.val.complex)); + jv_free(j); + return hash; +} + +const char* jv_string_value(jv j) { + assert(jv_get_kind(j) == JV_KIND_STRING); + return jvp_string_ptr(&j.val.complex)->data; +} + +/* + * Objects (internal helpers) + */ + +struct object_slot { + int next; + jvp_string* string; + uint32_t hash; + jv value; +}; + +typedef struct { + jv_refcnt refcnt; + int first_free; + struct object_slot elements[]; +} jvp_object; + + +/* warning: complex justification of alignment */ +static jv_complex jvp_object_new(int size) { + // Allocates an object of (size) slots and (size*2) hash buckets. + + // size must be a power of two + assert(size > 0 && (size & (size - 1)) == 0); + jvp_object* obj = malloc(sizeof(jvp_object) + + sizeof(struct object_slot) * size + + sizeof(int) * (size * 2)); + obj->refcnt.count = 1; + for (int i=0; ielements[i].next = i - 1; + obj->elements[i].string = 0; + obj->elements[i].hash = 0; + obj->elements[i].value = JV_NULL; + } + obj->first_free = size - 1; + int* hashbuckets = (int*)(&obj->elements[size]); + jv_complex r = {&obj->refcnt, + {size*2 - 1, (char*)hashbuckets - (char*)obj}}; + for (int i=0; iptr; +} + +static uint32_t jvp_object_mask(jv_complex* o) { + return o->i[0]; +} + +static int jvp_object_size(jv_complex* o) { + return (o->i[0] + 1) >> 1; +} + +static int* jvp_object_buckets(jv_complex* o) { + int* buckets = (int*)((char*)o->ptr + o->i[1]); + assert(buckets == (int*)&jvp_object_ptr(o)->elements[jvp_object_size(o)]); + return buckets; +} + +static int* jvp_object_find_bucket(jv_complex* object, jvp_string* key) { + return jvp_object_buckets(object) + (jvp_object_mask(object) & jvp_string_hash(key)); +} + +static struct object_slot* jvp_object_get_slot(jv_complex* object, int slot) { + assert(slot == -1 || (slot >= 0 && slot < jvp_object_size(object))); + if (slot == -1) return 0; + else return &jvp_object_ptr(object)->elements[slot]; +} + +static struct object_slot* jvp_object_next_slot(jv_complex* object, struct object_slot* slot) { + return jvp_object_get_slot(object, slot->next); +} + +static struct object_slot* jvp_object_find_slot(jv_complex* object, jvp_string* keystr, int* bucket) { + for (struct object_slot* curr = jvp_object_get_slot(object, *bucket); + curr; + curr = jvp_object_next_slot(object, curr)) { + if (jvp_string_equal_hashed(keystr, curr->string)) { + return curr; + } + } + return 0; +} + +static struct object_slot* jvp_object_add_slot(jv_complex* object, jvp_string* key, int* bucket) { + jvp_object* o = jvp_object_ptr(object); + int newslot_idx = o->first_free; + struct object_slot* newslot = jvp_object_get_slot(object, newslot_idx); + if (newslot == 0) return 0; + o->first_free = newslot->next; + newslot->next = *bucket; + *bucket = newslot_idx; + newslot->hash = jvp_string_hash(key); + newslot->string = key; + return newslot; +} + +static void jvp_object_free_slot(jv_complex* object, struct object_slot* slot) { + jvp_object* o = jvp_object_ptr(object); + slot->next = o->first_free; + assert(slot->string); + jvp_string_free_p(slot->string); + slot->string = 0; + jv_free(slot->value); + o->first_free = slot - jvp_object_get_slot(object, 0); +} + +static jv* jvp_object_read(jv_complex* object, jvp_string* key) { + int* bucket = jvp_object_find_bucket(object, key); + struct object_slot* slot = jvp_object_find_slot(object, key, bucket); + if (slot == 0) return 0; + else return &slot->value; +} + +static void jvp_object_free(jv_complex* o) { + if (jvp_refcnt_dec(o)) { + for (int i=0; istring) { + jvp_string_free_p(slot->string); + jv_free(slot->value); + } + } + free(jvp_object_ptr(o)); + } +} + +static void jvp_object_rehash(jv_complex* object) { + assert(jvp_refcnt_unshared(object)); + int size = jvp_object_size(object); + jv_complex new_object = jvp_object_new(size * 2); + for (int i=0; istring) continue; + + int* new_bucket = jvp_object_find_bucket(&new_object, slot->string); + assert(!jvp_object_find_slot(&new_object, slot->string, new_bucket)); + struct object_slot* new_slot = jvp_object_add_slot(&new_object, slot->string, new_bucket); + assert(new_slot); + new_slot->value = slot->value; + } + // references are transported, just drop the old table + free(jvp_object_ptr(object)); + *object = new_object; +} + +static void jvp_object_unshare(jv_complex* object) { + if (jvp_refcnt_unshared(object)) + return; + + jv_complex new_object = jvp_object_new(jvp_object_size(object)); + jvp_object_ptr(&new_object)->first_free = jvp_object_ptr(object)->first_free; + for (int i=0; istring) { + new_slot->string = jvp_string_copy_p(old_slot->string); + new_slot->value = jv_copy(old_slot->value); + } + } + + int* old_buckets = jvp_object_buckets(object); + int* new_buckets = jvp_object_buckets(&new_object); + memcpy(new_buckets, old_buckets, sizeof(int) * jvp_object_size(&new_object)*2); + + jvp_object_free(object); + *object = new_object; + assert(jvp_refcnt_unshared(object)); +} + +static jv* jvp_object_write(jv_complex* object, jvp_string* key) { + jvp_object_unshare(object); + int* bucket = jvp_object_find_bucket(object, key); + struct object_slot* slot = jvp_object_find_slot(object, key, bucket); + if (slot) { + // already has the key + jvp_string_free_p(key); + } else { + slot = jvp_object_add_slot(object, key, bucket); + } + if (slot == 0) { + jvp_object_rehash(object); + bucket = jvp_object_find_bucket(object, key); + assert(!jvp_object_find_slot(object, key, bucket)); + slot = jvp_object_add_slot(object, key, bucket); + assert(slot); + } + return &slot->value; +} + +static int jvp_object_delete(jv_complex* object, jvp_string* key) { + jvp_object_unshare(object); + int* bucket = jvp_object_find_bucket(object, key); + int* prev_ptr = bucket; + for (struct object_slot* curr = jvp_object_get_slot(object, *bucket); + curr; + curr = jvp_object_next_slot(object, curr)) { + if (jvp_string_equal_hashed(key, curr->string)) { + *prev_ptr = curr->next; + jvp_object_free_slot(object, curr); + return 1; + } + prev_ptr = &curr->next; + } + return 0; +} + +/* + * Objects (public interface) + */ +#define DEFAULT_OBJECT_SIZE 8 +jv jv_object() { + jv j; + j.kind = JV_KIND_OBJECT; + j.val.complex = jvp_object_new(8); + return j; +} + +jv jv_object_get(jv object, jv key) { + assert(jv_get_kind(object) == JV_KIND_OBJECT); + assert(jv_get_kind(key) == JV_KIND_STRING); + jv val = jv_copy(*jvp_object_read(&object.val.complex, jvp_string_ptr(&key.val.complex))); + jv_free(object); + jv_free(key); + return val; +} + +jv jv_object_set(jv object, jv key, jv value) { + assert(jv_get_kind(object) == JV_KIND_OBJECT); + assert(jv_get_kind(key) == JV_KIND_STRING); + // copy/free of object, key, value coalesced + *jvp_object_write(&object.val.complex, jvp_string_ptr(&key.val.complex)) = value; + return object; +} + +jv jv_object_delete(jv object, jv key) { + assert(jv_get_kind(object) == JV_KIND_OBJECT); + assert(jv_get_kind(key) == JV_KIND_STRING); + jvp_object_delete(&object.val.complex, jvp_string_ptr(&key.val.complex)); + jv_free(key); + return object; +} + +/* + * Object iteration (internal helpers) + */ + +enum { ITER_FINISHED = -2 }; + +int jv_object_iter_valid(jv object, int i) { + return i != ITER_FINISHED; +} + +int jv_object_iter(jv object) { + assert(jv_get_kind(object) == JV_KIND_OBJECT); + return jv_object_iter_next(object, -1); +} + +int jv_object_iter_next(jv object, int iter) { + assert(jv_get_kind(object) == JV_KIND_OBJECT); + assert(iter != ITER_FINISHED); + jv_complex* o = &object.val.complex; + struct object_slot* slot; + do { + iter++; + if (iter >= jvp_object_size(o)) + return ITER_FINISHED; + slot = jvp_object_get_slot(o, iter); + } while (!slot->string); + return iter; +} + +jv jv_object_iter_key(jv object, int iter) { + jvp_string* s = jvp_object_get_slot(&object.val.complex, iter)->string; + assert(s); + jv j; + j.kind = JV_KIND_STRING; + j.val.complex.ptr = &s->refcnt; + j.val.complex.i[0] = 0; + j.val.complex.i[1] = 0; + return jv_copy(j); +} + +jv jv_object_iter_value(jv object, int iter) { + return jv_copy(jvp_object_get_slot(&object.val.complex, iter)->value); +} + +/* + * Memory management + */ +jv jv_copy(jv j) { + if (jv_get_kind(j) == JV_KIND_ARRAY || + jv_get_kind(j) == JV_KIND_STRING || + jv_get_kind(j) == JV_KIND_OBJECT) { + jvp_refcnt_inc(&j.val.complex); + } + return j; +} + +void jv_free(jv j) { + if (jv_get_kind(j) == JV_KIND_ARRAY) { + jvp_array_free(&j.val.complex); + } else if (jv_get_kind(j) == JV_KIND_STRING) { + jvp_string_free(&j.val.complex); + } else if (jv_get_kind(j) == JV_KIND_OBJECT) { + jvp_object_free(&j.val.complex); + } +} + +/* + * Higher-level operations + */ + +int jv_equal(jv a, jv b) { + int r; + if (jv_get_kind(a) != jv_get_kind(b)) { + r = 0; + } else { + switch (jv_get_kind(a)) { + case JV_KIND_NUMBER: + r = jv_number_value(a) == jv_number_value(b); + break; + case JV_KIND_ARRAY: { + r = jvp_array_equal(&a.val.complex, &b.val.complex); + break; + } + case JV_KIND_STRING: { + r = jvp_string_equal(&a.val.complex, &b.val.complex); + break; + } + default: + r = 1; + break; + } + } + jv_free(a); + jv_free(b); + return r; +} diff --git a/c/jv.h b/c/jv.h index fc964fa9..52158b72 100644 --- a/c/jv.h +++ b/c/jv.h @@ -2,6 +2,8 @@ #define JV_H #include +#include +#include static json_t* jv_lookup(json_t* t, json_t* k) { json_t* v; @@ -38,4 +40,102 @@ static json_t* jv_insert(json_t* root, json_t* value, json_t** path, int pathlen } + + +typedef enum { + JV_KIND_NULL, + JV_KIND_FALSE, + JV_KIND_TRUE, + JV_KIND_NUMBER, + JV_KIND_STRING, + JV_KIND_OBJECT, + JV_KIND_ARRAY +} jv_kind; + +typedef struct { + size_t count; +} jv_refcnt; + +typedef struct{ + jv_refcnt* ptr; + int i[2]; +} jv_complex; + +typedef struct { + jv_kind kind; + union { + double number; + jv_complex complex; + } val; +} jv; + +/* + * All jv_* functions consume (decref) input and produce (incref) output + * Except jv_copy + */ + +jv_kind jv_get_kind(jv); + +jv jv_copy(jv); +void jv_free(jv); + +int jv_equal(jv, jv); + +jv jv_null(); +jv jv_true(); +jv jv_false(); + +jv jv_number(double); +double jv_number_value(jv); + +jv jv_array(); +jv jv_array_sized(int); +int jv_array_length(jv); +jv jv_array_get(jv, int); +jv jv_array_set(jv, int, jv); +jv jv_array_append(jv, jv); +jv jv_array_concat(jv, jv); +jv jv_array_slice(jv, int, int); + + +jv jv_string(char*); +jv jv_string_sized(char*, int); +int jv_string_length(jv); +uint32_t jv_string_hash(jv); +const char* jv_string_value(jv); + +jv jv_object(); +jv jv_object_get(jv object, jv key); +jv jv_object_set(jv object, jv key, jv value); +jv jv_object_delete(jv object, jv key); + +int jv_object_iter(jv); +int jv_object_iter_next(jv, int); +int jv_object_iter_valid(jv, int); +jv jv_object_iter_key(jv, int); +jv jv_object_iter_value(jv, int); + + #endif + + +/* + +true/false/null: +check kind + +number: +introduce/eliminate jv +to integer + +array: +copy +free +slice +index +update + +updateslice? + + + */ diff --git a/c/jv_print.c b/c/jv_print.c new file mode 100644 index 00000000..b26d0b36 --- /dev/null +++ b/c/jv_print.c @@ -0,0 +1,45 @@ +#include "jv.h" +#include + +void jv_dump(jv x) { + switch (jv_get_kind(x)) { + case JV_KIND_NULL: + printf("null"); + break; + case JV_KIND_FALSE: + printf("false"); + break; + case JV_KIND_TRUE: + printf("true"); + break; + case JV_KIND_NUMBER: + printf("%f", jv_number_value(x)); + break; + case JV_KIND_STRING: + // FIXME: all sorts of broken + printf("\"%s\"", jv_string_value(x)); + break; + case JV_KIND_ARRAY: { + printf("["); + for (int i=0; i +#include +#include +#include "jv.h" + +void jv_dump(jv); + +int main(){ + /// Arrays and numbers + { + jv a = jv_array(); + assert(jv_get_kind(a) == JV_KIND_ARRAY); + assert(jv_array_length(jv_copy(a)) == 0); + assert(jv_array_length(jv_copy(a)) == 0); + + a = jv_array_append(a, jv_number(42)); + assert(jv_array_length(jv_copy(a)) == 1); + assert(jv_number_value(jv_array_get(jv_copy(a), 0)) == 42); + + jv a2 = jv_array_append(jv_array(), jv_number(42)); + assert(jv_equal(jv_copy(a), jv_copy(a))); + assert(jv_equal(jv_copy(a2), jv_copy(a2))); + assert(jv_equal(jv_copy(a), jv_copy(a2))); + assert(jv_equal(jv_copy(a2), jv_copy(a))); + jv_free(a2); + + a2 = jv_array_append(jv_array(), jv_number(19)); + assert(!jv_equal(jv_copy(a), jv_copy(a2))); + assert(!jv_equal(jv_copy(a2), jv_copy(a))); + jv_free(a2); + + + assert(a.val.complex.ptr->count == 1); + a = jv_array_append(a, jv_copy(a)); + assert(a.val.complex.ptr->count == 1); + + assert(jv_array_length(jv_copy(a)) == 2); + assert(jv_number_value(jv_array_get(jv_copy(a), 0)) == 42); + + for (int i=0; i<10; i++) { + jv subarray = jv_array_get(jv_copy(a), 1); + assert(jv_get_kind(subarray) == JV_KIND_ARRAY); + assert(jv_array_length(jv_copy(subarray)) == 1); + assert(jv_number_value(jv_array_get(jv_copy(subarray), 0)) == 42); + jv_free(subarray); + } + + + jv subarray = jv_array_get(jv_copy(a), 1); + assert(jv_get_kind(subarray) == JV_KIND_ARRAY); + assert(jv_array_length(jv_copy(subarray)) == 1); + assert(jv_number_value(jv_array_get(jv_copy(subarray), 0)) == 42); + + jv sub2 = jv_copy(subarray); + sub2 = jv_array_append(sub2, jv_number(19)); + + assert(jv_get_kind(sub2) == JV_KIND_ARRAY); + assert(jv_array_length(jv_copy(sub2)) == 2); + assert(jv_number_value(jv_array_get(jv_copy(sub2), 0)) == 42); + assert(jv_number_value(jv_array_get(jv_copy(sub2), 1)) == 19); + + assert(jv_get_kind(subarray) == JV_KIND_ARRAY); + assert(jv_array_length(jv_copy(subarray)) == 1); + assert(jv_number_value(jv_array_get(jv_copy(subarray), 0)) == 42); + + jv_free(subarray); + + void* before = sub2.val.complex.ptr; + sub2 = jv_array_append(sub2, jv_number(200)); + void* after = sub2.val.complex.ptr; + assert(before == after); + jv_free(sub2); + + jv a3 = jv_array_append(jv_copy(a), jv_number(19)); + assert(jv_array_length(jv_copy(a3)) == 3); + assert(jv_number_value(jv_array_get(jv_copy(a3), 0)) == 42); + assert(jv_array_length(jv_array_get(jv_copy(a3), 1)) == 1); + assert(jv_number_value(jv_array_get(jv_copy(a3), 2)) == 19); + jv_free(a3); + + + assert(jv_array_length(jv_copy(a)) == 2); + assert(jv_number_value(jv_array_get(jv_copy(a), 0)) == 42); + assert(jv_array_length(jv_array_get(jv_copy(a), 1)) == 1); + + + jv_dump(jv_copy(a)); printf("\n"); + jv_free(a); + } + + + /// Strings + { + assert(jv_equal(jv_string("foo"), jv_string_sized("foo", 3))); + char nasty[] = "foo\0"; + jv shortstr = jv_string(nasty), longstr = jv_string_sized(nasty, sizeof(nasty)); + assert(jv_string_length(shortstr) == strlen(nasty)); + assert(jv_string_length(longstr) == sizeof(nasty)); + + + char a1s[] = "hello", a2s[] = "hello", bs[] = "goodbye"; + jv a1 = jv_string(a1s), a2 = jv_string(a2s), b = jv_string(bs); + assert(jv_equal(jv_copy(a1), jv_copy(a2))); + assert(jv_equal(jv_copy(a2), jv_copy(a1))); + assert(!jv_equal(jv_copy(a1), jv_copy(b))); + + assert(jv_string_hash(jv_copy(a1)) == jv_string_hash(jv_copy(a1))); + assert(jv_string_hash(jv_copy(a1)) == jv_string_hash(jv_copy(a2))); + assert(jv_string_hash(jv_copy(b)) != jv_string_hash(jv_copy(a1))); + jv_free(a1); + jv_free(a2); + jv_free(b); + } + + /// Objects + { + jv o1 = jv_object(); + o1 = jv_object_set(o1, jv_string("foo"), jv_number(42)); + o1 = jv_object_set(o1, jv_string("bar"), jv_number(24)); + assert(jv_number_value(jv_object_get(jv_copy(o1), jv_string("foo"))) == 42); + assert(jv_number_value(jv_object_get(jv_copy(o1), jv_string("bar"))) == 24); + + jv o2 = jv_object_set(jv_copy(o1), jv_string("foo"), jv_number(420)); + o2 = jv_object_set(o2, jv_string("bar"), jv_number(240)); + assert(jv_number_value(jv_object_get(jv_copy(o1), jv_string("foo"))) == 42); + assert(jv_number_value(jv_object_get(jv_copy(o1), jv_string("bar"))) == 24); + assert(jv_number_value(jv_object_get(jv_copy(o2), jv_string("foo"))) == 420); + jv_free(o1); + assert(jv_number_value(jv_object_get(jv_copy(o2), jv_string("bar"))) == 240); + + jv_dump(jv_copy(o2)); printf("\n"); + + jv_free(o2); + } +} From f25cb16e6b889c5398391dbbf7179ce49c8a555a Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 28 Aug 2012 18:38:30 +0100 Subject: [PATCH 014/284] Fix a bug in lexical scoping, add tests --- c/compile.c | 5 ++++- c/execute.c | 11 ++++++++--- c/frame_layout.h | 11 ----------- c/testdata | 6 ++++++ 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/c/compile.c b/c/compile.c index f9f738d8..dc90aed3 100644 --- a/c/compile.c +++ b/c/compile.c @@ -418,7 +418,10 @@ static void compile(struct bytecode* bc, block b) { default: assert(0 && "Unknown type of argument"); case CLOSURE_CREATE: code[pos++] = curr->bound_by->imm.intval | ARG_NEWCLOSURE; - if (i == 0) desired_params = bc->subfunctions[curr->bound_by->imm.intval]->nclosures; + if (i == 0) { + inst* i = curr->bound_by; + desired_params = i->compiled->subfunctions[i->imm.intval]->nclosures; + } break; case CLOSURE_PARAM: code[pos++] = curr->bound_by->imm.intval; diff --git a/c/execute.c b/c/execute.c index 75aaec09..9aa85b29 100644 --- a/c/execute.c +++ b/c/execute.c @@ -104,9 +104,10 @@ static struct closure make_closure(struct forkable_stack* stk, frame_ptr fr, uin if (idx & ARG_NEWCLOSURE) { int subfn_idx = idx & ~ARG_NEWCLOSURE; assert(subfn_idx < frame_self(fr)->bc->nsubfunctions); - return closure_new(stk, frame_self(fr)->bc->subfunctions[subfn_idx]); + struct closure cl = {frame_self(fr)->bc->subfunctions[subfn_idx], + forkable_stack_to_idx(stk, fr)}; + return cl; } else { - // FIXME: set pc return *frame_closure_arg(fr, idx); } } @@ -214,6 +215,9 @@ json_t* jq_next() { uint16_t v = *pc++; frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); json_t** var = frame_local_var(fp, v); + printf("V%d = ", v); + json_dumpf(*var, stdout, JSON_ENCODE_ANY); + printf("\n"); stack_push(stackval_replace(stack_pop(), *var)); break; } @@ -411,7 +415,8 @@ void jq_init(struct bytecode* bc, json_t* input) { forkable_stack_init(&fork_stk, 10240); // FIXME: lower this number, see if it breaks stack_push(stackval_root(input)); - frame_push(&frame_stk, closure_new_toplevel(bc), 0); + struct closure top = {bc, -1}; + frame_push(&frame_stk, top, 0); frame_push_backtrack(&frame_stk, bc->code); } diff --git a/c/frame_layout.h b/c/frame_layout.h index b2e590eb..fcbd1dc3 100644 --- a/c/frame_layout.h +++ b/c/frame_layout.h @@ -79,17 +79,6 @@ static frame_ptr frame_get_level(struct forkable_stack* stk, frame_ptr fr, int l return fr; } -static struct closure closure_new_toplevel(struct bytecode* bc) { - struct closure cl = {bc, -1}; - return cl; -} - -static struct closure closure_new(struct forkable_stack* stk, struct bytecode* bc) { - struct closure cl = {bc, - forkable_stack_to_idx(stk, frame_current(stk))}; - return cl; -} - static frame_ptr frame_push(struct forkable_stack* stk, struct closure cl, uint16_t* retaddr) { frame_ptr fp = forkable_stack_push(stk, frame_size(cl.bc)); struct continuation* cc = frame_self(fp); diff --git a/c/testdata b/c/testdata index 6e40b9ae..95e40781 100644 --- a/c/testdata +++ b/c/testdata @@ -143,6 +143,8 @@ def f: (1000,2000); f 1000 2000 +# test backtracking through function calls and returns +# this test is *evil* [[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | g; f[0] | [f][0][1] | f] "woo, testing!" [[110.0, 130.0], [210.0, 130.0], [110.0, 230.0], [210.0, 230.0], [120.0, 160.0], [220.0, 160.0], [120.0, 260.0], [220.0, 260.0]] @@ -154,3 +156,7 @@ def f(x): x | x; f([.], . + [42]) [[1,2,3,42]] [1,2,3,42,42] +# test closures and lexical scoping +def id(x):x; 2000 as $x | def f(x):1 as $x | id([$x, x, x]); def g(x): 100 as $x | f($x,$x+x); g($x) +"more testing" +[1,100,2100.0,100,2100.0] From 9e544c55dc82780161c93665099bad6dffab3cf7 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sat, 1 Sep 2012 16:50:25 +0100 Subject: [PATCH 015/284] Import a copy of David Gay's dtoa.c --- c/dtoa.c | 4357 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4357 insertions(+) create mode 100644 c/dtoa.c diff --git a/c/dtoa.c b/c/dtoa.c new file mode 100644 index 00000000..41ed6982 --- /dev/null +++ b/c/dtoa.c @@ -0,0 +1,4357 @@ +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* Please send bug reports to David M. Gay (dmg at acm dot org, + * with " at " changed at "@" and " dot " changed to "."). */ + +/* On a machine with IEEE extended-precision registers, it is + * necessary to specify double-precision (53-bit) rounding precision + * before invoking strtod or dtoa. If the machine uses (the equivalent + * of) Intel 80x87 arithmetic, the call + * _control87(PC_53, MCW_PC); + * does this with many compilers. Whether this or another call is + * appropriate depends on the compiler; for this to work, it may be + * necessary to #include "float.h" or another system-dependent header + * file. + */ + +/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. + * (Note that IEEE arithmetic is disabled by gcc's -ffast-math flag.) + * + * This strtod returns a nearest machine number to the input decimal + * string (or sets errno to ERANGE). With IEEE arithmetic, ties are + * broken by the IEEE round-even rule. Otherwise ties are broken by + * biased rounding (add half and chop). + * + * Inspired loosely by William D. Clinger's paper "How to Read Floating + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * + * 1. We only require IEEE, IBM, or VAX double-precision + * arithmetic (not IEEE double-extended). + * 2. We get by with floating-point arithmetic in a case that + * Clinger missed -- when we're computing d * 10^n + * for a small integer d and the integer n is not too + * much larger than 22 (the maximum integer k for which + * we can represent 10^k exactly), we may be able to + * compute (d*10^k) * 10^(e-k) with just one roundoff. + * 3. Rather than a bit-at-a-time adjustment of the binary + * result in the hard case, we use floating-point + * arithmetic to determine the adjustment to within + * one bit; only in really hard cases do we need to + * compute a second residual. + * 4. Because of 3., we don't need a large table of powers of 10 + * for ten-to-e (just some small tables, e.g. of 10^k + * for 0 <= k <= 22). + */ + +/* + * #define IEEE_8087 for IEEE-arithmetic machines where the least + * significant byte has the lowest address. + * #define IEEE_MC68k for IEEE-arithmetic machines where the most + * significant byte has the lowest address. + * #define Long int on machines with 32-bit ints and 64-bit longs. + * #define IBM for IBM mainframe-style floating-point arithmetic. + * #define VAX for VAX-style floating-point arithmetic (D_floating). + * #define No_leftright to omit left-right logic in fast floating-point + * computation of dtoa. This will cause dtoa modes 4 and 5 to be + * treated the same as modes 2 and 3 for some inputs. + * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and strtod and dtoa should round accordingly. Unless Trust_FLT_ROUNDS + * is also #defined, fegetround() will be queried for the rounding mode. + * Note that both FLT_ROUNDS and fegetround() are specified by the C99 + * standard (and are specified to be consistent, with fesetround() + * affecting the value of FLT_ROUNDS), but that some (Linux) systems + * do not work correctly in this regard, so using fegetround() is more + * portable than using FLT_ROUNDS directly. + * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and Honor_FLT_ROUNDS is not #defined. + * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines + * that use extended-precision instructions to compute rounded + * products and quotients) with IBM. + * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic + * that rounds toward +Infinity. + * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased + * rounding when the underlying floating-point arithmetic uses + * unbiased rounding. This prevent using ordinary floating-point + * arithmetic when the result could be computed with one rounding error. + * #define Inaccurate_Divide for IEEE-format with correctly rounded + * products but inaccurate quotients, e.g., for Intel i860. + * #define NO_LONG_LONG on machines that do not have a "long long" + * integer type (of >= 64 bits). On such machines, you can + * #define Just_16 to store 16 bits per 32-bit Long when doing + * high-precision integer arithmetic. Whether this speeds things + * up or slows things down depends on the machine and the number + * being converted. If long long is available and the name is + * something other than "long long", #define Llong to be the name, + * and if "unsigned Llong" does not work as an unsigned version of + * Llong, #define #ULLong to be the corresponding unsigned type. + * #define KR_headers for old-style C function headers. + * #define Bad_float_h if your system lacks a float.h or if it does not + * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, + * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. + * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) + * if memory is available and otherwise does something you deem + * appropriate. If MALLOC is undefined, malloc will be invoked + * directly -- and assumed always to succeed. Similarly, if you + * want something other than the system's free() to be called to + * recycle memory acquired from MALLOC, #define FREE to be the + * name of the alternate routine. (FREE or free is only called in + * pathological cases, e.g., in a dtoa call after a dtoa return in + * mode 3 with thousands of digits requested.) + * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making + * memory allocations from a private pool of memory when possible. + * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, + * unless #defined to be a different length. This default length + * suffices to get rid of MALLOC calls except for unusual cases, + * such as decimal-to-binary conversion of a very long string of + * digits. The longest string dtoa can return is about 751 bytes + * long. For conversions by strtod of strings of 800 digits and + * all dtoa conversions in single-threaded executions with 8-byte + * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte + * pointers, PRIVATE_MEM >= 7112 appears adequate. + * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK + * #defined automatically on IEEE systems. On such systems, + * when INFNAN_CHECK is #defined, strtod checks + * for Infinity and NaN (case insensitively). On some systems + * (e.g., some HP systems), it may be necessary to #define NAN_WORD0 + * appropriately -- to the most significant word of a quiet NaN. + * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) + * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, + * strtod also accepts (case insensitively) strings of the form + * NaN(x), where x is a string of hexadecimal digits and spaces; + * if there is only one string of hexadecimal digits, it is taken + * for the 52 fraction bits of the resulting NaN; if there are two + * or more strings of hex digits, the first is for the high 20 bits, + * the second and subsequent for the low 32 bits, with intervening + * white space ignored; but if this results in none of the 52 + * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 + * and NAN_WORD1 are used instead. + * #define MULTIPLE_THREADS if the system offers preemptively scheduled + * multiple threads. In this case, you must provide (or suitably + * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed + * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed + * in pow5mult, ensures lazy evaluation of only one copy of high + * powers of 5; omitting this lock would introduce a small + * probability of wasting memory, but would otherwise be harmless.) + * You must also invoke freedtoa(s) to free the value s returned by + * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. + * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that + * avoids underflows on inputs whose result does not underflow. + * If you #define NO_IEEE_Scale on a machine that uses IEEE-format + * floating-point numbers and flushes underflows to zero rather + * than implementing gradual underflow, then you must also #define + * Sudden_Underflow. + * #define USE_LOCALE to use the current locale's decimal_point value. + * #define SET_INEXACT if IEEE arithmetic is being used and extra + * computation should be done to set the inexact flag when the + * result is inexact and avoid setting inexact when the result + * is exact. In this case, dtoa.c must be compiled in + * an environment, perhaps provided by #include "dtoa.c" in a + * suitable wrapper, that defines two functions, + * int get_inexact(void); + * void clear_inexact(void); + * such that get_inexact() returns a nonzero value if the + * inexact bit is already set, and clear_inexact() sets the + * inexact bit to 0. When SET_INEXACT is #defined, strtod + * also does extra computations to set the underflow and overflow + * flags when appropriate (i.e., when the result is tiny and + * inexact or when it is a numeric value rounded to +-infinity). + * #define NO_ERRNO if strtod should not assign errno = ERANGE when + * the result overflows to +-Infinity or underflows to 0. + * #define NO_HEX_FP to omit recognition of hexadecimal floating-point + * values by strtod. + * #define NO_STRTOD_BIGCOMP (on IEEE-arithmetic systems only for now) + * to disable logic for "fast" testing of very long input strings + * to strtod. This testing proceeds by initially truncating the + * input string, then if necessary comparing the whole string with + * a decimal expansion to decide close cases. This logic is only + * used for input more than STRTOD_DIGLIM digits long (default 40). + */ + +#ifndef Long +#define Long long +#endif +#ifndef ULong +typedef unsigned Long ULong; +#endif + +#ifdef DEBUG +#include "stdio.h" +#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} +#endif + +#include "stdlib.h" +#include "string.h" + +#ifdef USE_LOCALE +#include "locale.h" +#endif + +#ifdef Honor_FLT_ROUNDS +#ifndef Trust_FLT_ROUNDS +#include +#endif +#endif + +#ifdef MALLOC +#ifdef KR_headers +extern char *MALLOC(); +#else +extern void *MALLOC(size_t); +#endif +#else +#define MALLOC malloc +#endif + +#ifndef Omit_Private_Memory +#ifndef PRIVATE_MEM +#define PRIVATE_MEM 2304 +#endif +#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) +static double private_mem[PRIVATE_mem], *pmem_next = private_mem; +#endif + +#undef IEEE_Arith +#undef Avoid_Underflow +#ifdef IEEE_MC68k +#define IEEE_Arith +#endif +#ifdef IEEE_8087 +#define IEEE_Arith +#endif + +#ifdef IEEE_Arith +#ifndef NO_INFNAN_CHECK +#undef INFNAN_CHECK +#define INFNAN_CHECK +#endif +#else +#undef INFNAN_CHECK +#define NO_STRTOD_BIGCOMP +#endif + +#include "errno.h" + +#ifdef Bad_float_h + +#ifdef IEEE_Arith +#define DBL_DIG 15 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX_EXP 1024 +#define FLT_RADIX 2 +#endif /*IEEE_Arith*/ + +#ifdef IBM +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 75 +#define DBL_MAX_EXP 63 +#define FLT_RADIX 16 +#define DBL_MAX 7.2370055773322621e+75 +#endif + +#ifdef VAX +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 38 +#define DBL_MAX_EXP 127 +#define FLT_RADIX 2 +#define DBL_MAX 1.7014118346046923e+38 +#endif + +#ifndef LONG_MAX +#define LONG_MAX 2147483647 +#endif + +#else /* ifndef Bad_float_h */ +#include "float.h" +#endif /* Bad_float_h */ + +#ifndef __MATH_H__ +#include "math.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef CONST +#ifdef KR_headers +#define CONST /* blank */ +#else +#define CONST const +#endif +#endif + +#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 +Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. +#endif + +typedef union { double d; ULong L[2]; } U; + +#ifdef IEEE_8087 +#define word0(x) (x)->L[1] +#define word1(x) (x)->L[0] +#else +#define word0(x) (x)->L[0] +#define word1(x) (x)->L[1] +#endif +#define dval(x) (x)->d + +#ifndef STRTOD_DIGLIM +#define STRTOD_DIGLIM 40 +#endif + +#ifdef DIGLIM_DEBUG +extern int strtod_diglim; +#else +#define strtod_diglim STRTOD_DIGLIM +#endif + +/* The following definition of Storeinc is appropriate for MIPS processors. + * An alternative that might be better on some machines is + * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) + */ +#if defined(IEEE_8087) + defined(VAX) +#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ +((unsigned short *)a)[0] = (unsigned short)c, a++) +#else +#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ +((unsigned short *)a)[1] = (unsigned short)c, a++) +#endif + +/* #define P DBL_MANT_DIG */ +/* Ten_pmax = floor(P*log(2)/log(5)) */ +/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ +/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ +/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ + +#ifdef IEEE_Arith +#define Exp_shift 20 +#define Exp_shift1 20 +#define Exp_msk1 0x100000 +#define Exp_msk11 0x100000 +#define Exp_mask 0x7ff00000 +#define P 53 +#define Nbits 53 +#define Bias 1023 +#define Emax 1023 +#define Emin (-1022) +#define Exp_1 0x3ff00000 +#define Exp_11 0x3ff00000 +#define Ebits 11 +#define Frac_mask 0xfffff +#define Frac_mask1 0xfffff +#define Ten_pmax 22 +#define Bletch 0x10 +#define Bndry_mask 0xfffff +#define Bndry_mask1 0xfffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 1 +#define Tiny0 0 +#define Tiny1 1 +#define Quick_max 14 +#define Int_max 14 +#ifndef NO_IEEE_Scale +#define Avoid_Underflow +#ifdef Flush_Denorm /* debugging option */ +#undef Sudden_Underflow +#endif +#endif + +#ifndef Flt_Rounds +#ifdef FLT_ROUNDS +#define Flt_Rounds FLT_ROUNDS +#else +#define Flt_Rounds 1 +#endif +#endif /*Flt_Rounds*/ + +#ifdef Honor_FLT_ROUNDS +#undef Check_FLT_ROUNDS +#define Check_FLT_ROUNDS +#else +#define Rounding Flt_Rounds +#endif + +#else /* ifndef IEEE_Arith */ +#undef Check_FLT_ROUNDS +#undef Honor_FLT_ROUNDS +#undef SET_INEXACT +#undef Sudden_Underflow +#define Sudden_Underflow +#ifdef IBM +#undef Flt_Rounds +#define Flt_Rounds 0 +#define Exp_shift 24 +#define Exp_shift1 24 +#define Exp_msk1 0x1000000 +#define Exp_msk11 0x1000000 +#define Exp_mask 0x7f000000 +#define P 14 +#define Nbits 56 +#define Bias 65 +#define Emax 248 +#define Emin (-260) +#define Exp_1 0x41000000 +#define Exp_11 0x41000000 +#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ +#define Frac_mask 0xffffff +#define Frac_mask1 0xffffff +#define Bletch 4 +#define Ten_pmax 22 +#define Bndry_mask 0xefffff +#define Bndry_mask1 0xffffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 4 +#define Tiny0 0x100000 +#define Tiny1 0 +#define Quick_max 14 +#define Int_max 15 +#else /* VAX */ +#undef Flt_Rounds +#define Flt_Rounds 1 +#define Exp_shift 23 +#define Exp_shift1 7 +#define Exp_msk1 0x80 +#define Exp_msk11 0x800000 +#define Exp_mask 0x7f80 +#define P 56 +#define Nbits 56 +#define Bias 129 +#define Emax 126 +#define Emin (-129) +#define Exp_1 0x40800000 +#define Exp_11 0x4080 +#define Ebits 8 +#define Frac_mask 0x7fffff +#define Frac_mask1 0xffff007f +#define Ten_pmax 24 +#define Bletch 2 +#define Bndry_mask 0xffff007f +#define Bndry_mask1 0xffff007f +#define LSB 0x10000 +#define Sign_bit 0x8000 +#define Log2P 1 +#define Tiny0 0x80 +#define Tiny1 0 +#define Quick_max 15 +#define Int_max 15 +#endif /* IBM, VAX */ +#endif /* IEEE_Arith */ + +#ifndef IEEE_Arith +#define ROUND_BIASED +#else +#ifdef ROUND_BIASED_without_Round_Up +#undef ROUND_BIASED +#define ROUND_BIASED +#endif +#endif + +#ifdef RND_PRODQUOT +#define rounded_product(a,b) a = rnd_prod(a, b) +#define rounded_quotient(a,b) a = rnd_quot(a, b) +#ifdef KR_headers +extern double rnd_prod(), rnd_quot(); +#else +extern double rnd_prod(double, double), rnd_quot(double, double); +#endif +#else +#define rounded_product(a,b) a *= b +#define rounded_quotient(a,b) a /= b +#endif + +#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) +#define Big1 0xffffffff + +#ifndef Pack_32 +#define Pack_32 +#endif + +typedef struct BCinfo BCinfo; + struct +BCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflchk; }; + +#ifdef KR_headers +#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff) +#else +#define FFFFFFFF 0xffffffffUL +#endif + +#ifdef NO_LONG_LONG +#undef ULLong +#ifdef Just_16 +#undef Pack_32 +/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. + * This makes some inner loops simpler and sometimes saves work + * during multiplications, but it often seems to make things slightly + * slower. Hence the default is now to store 32 bits per Long. + */ +#endif +#else /* long long available */ +#ifndef Llong +#define Llong long long +#endif +#ifndef ULLong +#define ULLong unsigned Llong +#endif +#endif /* NO_LONG_LONG */ + +#ifndef MULTIPLE_THREADS +#define ACQUIRE_DTOA_LOCK(n) /*nothing*/ +#define FREE_DTOA_LOCK(n) /*nothing*/ +#endif + +#define Kmax 7 + +#ifdef __cplusplus +extern "C" double strtod(const char *s00, char **se); +extern "C" char *dtoa(double d, int mode, int ndigits, + int *decpt, int *sign, char **rve); +#endif + + struct +Bigint { + struct Bigint *next; + int k, maxwds, sign, wds; + ULong x[1]; + }; + + typedef struct Bigint Bigint; + + static Bigint *freelist[Kmax+1]; + + static Bigint * +Balloc +#ifdef KR_headers + (k) int k; +#else + (int k) +#endif +{ + int x; + Bigint *rv; +#ifndef Omit_Private_Memory + unsigned int len; +#endif + + ACQUIRE_DTOA_LOCK(0); + /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */ + /* but this case seems very unlikely. */ + if (k <= Kmax && (rv = freelist[k])) + freelist[k] = rv->next; + else { + x = 1 << k; +#ifdef Omit_Private_Memory + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); +#else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) + /sizeof(double); + if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) { + rv = (Bigint*)pmem_next; + pmem_next += len; + } + else + rv = (Bigint*)MALLOC(len*sizeof(double)); +#endif + rv->k = k; + rv->maxwds = x; + } + FREE_DTOA_LOCK(0); + rv->sign = rv->wds = 0; + return rv; + } + + static void +Bfree +#ifdef KR_headers + (v) Bigint *v; +#else + (Bigint *v) +#endif +{ + if (v) { + if (v->k > Kmax) +#ifdef FREE + FREE((void*)v); +#else + free((void*)v); +#endif + else { + ACQUIRE_DTOA_LOCK(0); + v->next = freelist[v->k]; + freelist[v->k] = v; + FREE_DTOA_LOCK(0); + } + } + } + +#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ +y->wds*sizeof(Long) + 2*sizeof(int)) + + static Bigint * +multadd +#ifdef KR_headers + (b, m, a) Bigint *b; int m, a; +#else + (Bigint *b, int m, int a) /* multiply by m and add a */ +#endif +{ + int i, wds; +#ifdef ULLong + ULong *x; + ULLong carry, y; +#else + ULong carry, *x, y; +#ifdef Pack_32 + ULong xi, z; +#endif +#endif + Bigint *b1; + + wds = b->wds; + x = b->x; + i = 0; + carry = a; + do { +#ifdef ULLong + y = *x * (ULLong)m + carry; + carry = y >> 32; + *x++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + xi = *x; + y = (xi & 0xffff) * m + carry; + z = (xi >> 16) * m + (y >> 16); + carry = z >> 16; + *x++ = (z << 16) + (y & 0xffff); +#else + y = *x * m + carry; + carry = y >> 16; + *x++ = y & 0xffff; +#endif +#endif + } + while(++i < wds); + if (carry) { + if (wds >= b->maxwds) { + b1 = Balloc(b->k+1); + Bcopy(b1, b); + Bfree(b); + b = b1; + } + b->x[wds++] = carry; + b->wds = wds; + } + return b; + } + + static Bigint * +s2b +#ifdef KR_headers + (s, nd0, nd, y9, dplen) CONST char *s; int nd0, nd, dplen; ULong y9; +#else + (const char *s, int nd0, int nd, ULong y9, int dplen) +#endif +{ + Bigint *b; + int i, k; + Long x, y; + + x = (nd + 8) / 9; + for(k = 0, y = 1; x > y; y <<= 1, k++) ; +#ifdef Pack_32 + b = Balloc(k); + b->x[0] = y9; + b->wds = 1; +#else + b = Balloc(k+1); + b->x[0] = y9 & 0xffff; + b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; +#endif + + i = 9; + if (9 < nd0) { + s += 9; + do b = multadd(b, 10, *s++ - '0'); + while(++i < nd0); + s += dplen; + } + else + s += dplen + 9; + for(; i < nd; i++) + b = multadd(b, 10, *s++ - '0'); + return b; + } + + static int +hi0bits +#ifdef KR_headers + (x) ULong x; +#else + (ULong x) +#endif +{ + int k = 0; + + if (!(x & 0xffff0000)) { + k = 16; + x <<= 16; + } + if (!(x & 0xff000000)) { + k += 8; + x <<= 8; + } + if (!(x & 0xf0000000)) { + k += 4; + x <<= 4; + } + if (!(x & 0xc0000000)) { + k += 2; + x <<= 2; + } + if (!(x & 0x80000000)) { + k++; + if (!(x & 0x40000000)) + return 32; + } + return k; + } + + static int +lo0bits +#ifdef KR_headers + (y) ULong *y; +#else + (ULong *y) +#endif +{ + int k; + ULong x = *y; + + if (x & 7) { + if (x & 1) + return 0; + if (x & 2) { + *y = x >> 1; + return 1; + } + *y = x >> 2; + return 2; + } + k = 0; + if (!(x & 0xffff)) { + k = 16; + x >>= 16; + } + if (!(x & 0xff)) { + k += 8; + x >>= 8; + } + if (!(x & 0xf)) { + k += 4; + x >>= 4; + } + if (!(x & 0x3)) { + k += 2; + x >>= 2; + } + if (!(x & 1)) { + k++; + x >>= 1; + if (!x) + return 32; + } + *y = x; + return k; + } + + static Bigint * +i2b +#ifdef KR_headers + (i) int i; +#else + (int i) +#endif +{ + Bigint *b; + + b = Balloc(1); + b->x[0] = i; + b->wds = 1; + return b; + } + + static Bigint * +mult +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int k, wa, wb, wc; + ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; + ULong y; +#ifdef ULLong + ULLong carry, z; +#else + ULong carry, z; +#ifdef Pack_32 + ULong z2; +#endif +#endif + + if (a->wds < b->wds) { + c = a; + a = b; + b = c; + } + k = a->k; + wa = a->wds; + wb = b->wds; + wc = wa + wb; + if (wc > a->maxwds) + k++; + c = Balloc(k); + for(x = c->x, xa = x + wc; x < xa; x++) + *x = 0; + xa = a->x; + xae = xa + wa; + xb = b->x; + xbe = xb + wb; + xc0 = c->x; +#ifdef ULLong + for(; xb < xbe; xc0++) { + if ((y = *xb++)) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * (ULLong)y + *xc + carry; + carry = z >> 32; + *xc++ = z & FFFFFFFF; + } + while(x < xae); + *xc = carry; + } + } +#else +#ifdef Pack_32 + for(; xb < xbe; xb++, xc0++) { + if (y = *xb & 0xffff) { + x = xa; + xc = xc0; + carry = 0; + do { + z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; + carry = z >> 16; + z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; + carry = z2 >> 16; + Storeinc(xc, z2, z); + } + while(x < xae); + *xc = carry; + } + if (y = *xb >> 16) { + x = xa; + xc = xc0; + carry = 0; + z2 = *xc; + do { + z = (*x & 0xffff) * y + (*xc >> 16) + carry; + carry = z >> 16; + Storeinc(xc, z, z2); + z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; + carry = z2 >> 16; + } + while(x < xae); + *xc = z2; + } + } +#else + for(; xb < xbe; xc0++) { + if (y = *xb++) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * y + *xc + carry; + carry = z >> 16; + *xc++ = z & 0xffff; + } + while(x < xae); + *xc = carry; + } + } +#endif +#endif + for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; + c->wds = wc; + return c; + } + + static Bigint *p5s; + + static Bigint * +pow5mult +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + Bigint *b1, *p5, *p51; + int i; + static int p05[3] = { 5, 25, 125 }; + + if ((i = k & 3)) + b = multadd(b, p05[i-1], 0); + + if (!(k >>= 2)) + return b; + if (!(p5 = p5s)) { + /* first time */ +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p5 = p5s)) { + p5 = p5s = i2b(625); + p5->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p5 = p5s = i2b(625); + p5->next = 0; +#endif + } + for(;;) { + if (k & 1) { + b1 = mult(b, p5); + Bfree(b); + b = b1; + } + if (!(k >>= 1)) + break; + if (!(p51 = p5->next)) { +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p51 = p5->next)) { + p51 = p5->next = mult(p5,p5); + p51->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p51 = p5->next = mult(p5,p5); + p51->next = 0; +#endif + } + p5 = p51; + } + return b; + } + + static Bigint * +lshift +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + int i, k1, n, n1; + Bigint *b1; + ULong *x, *x1, *xe, z; + +#ifdef Pack_32 + n = k >> 5; +#else + n = k >> 4; +#endif + k1 = b->k; + n1 = n + b->wds + 1; + for(i = b->maxwds; n1 > i; i <<= 1) + k1++; + b1 = Balloc(k1); + x1 = b1->x; + for(i = 0; i < n; i++) + *x1++ = 0; + x = b->x; + xe = x + b->wds; +#ifdef Pack_32 + if (k &= 0x1f) { + k1 = 32 - k; + z = 0; + do { + *x1++ = *x << k | z; + z = *x++ >> k1; + } + while(x < xe); + if ((*x1 = z)) + ++n1; + } +#else + if (k &= 0xf) { + k1 = 16 - k; + z = 0; + do { + *x1++ = *x << k & 0xffff | z; + z = *x++ >> k1; + } + while(x < xe); + if (*x1 = z) + ++n1; + } +#endif + else do + *x1++ = *x++; + while(x < xe); + b1->wds = n1 - 1; + Bfree(b); + return b1; + } + + static int +cmp +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + ULong *xa, *xa0, *xb, *xb0; + int i, j; + + i = a->wds; + j = b->wds; +#ifdef DEBUG + if (i > 1 && !a->x[i-1]) + Bug("cmp called with a->x[a->wds-1] == 0"); + if (j > 1 && !b->x[j-1]) + Bug("cmp called with b->x[b->wds-1] == 0"); +#endif + if (i -= j) + return i; + xa0 = a->x; + xa = xa0 + j; + xb0 = b->x; + xb = xb0 + j; + for(;;) { + if (*--xa != *--xb) + return *xa < *xb ? -1 : 1; + if (xa <= xa0) + break; + } + return 0; + } + + static Bigint * +diff +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int i, wa, wb; + ULong *xa, *xae, *xb, *xbe, *xc; +#ifdef ULLong + ULLong borrow, y; +#else + ULong borrow, y; +#ifdef Pack_32 + ULong z; +#endif +#endif + + i = cmp(a,b); + if (!i) { + c = Balloc(0); + c->wds = 1; + c->x[0] = 0; + return c; + } + if (i < 0) { + c = a; + a = b; + b = c; + i = 1; + } + else + i = 0; + c = Balloc(a->k); + c->sign = i; + wa = a->wds; + xa = a->x; + xae = xa + wa; + wb = b->wds; + xb = b->x; + xbe = xb + wb; + xc = c->x; + borrow = 0; +#ifdef ULLong + do { + y = (ULLong)*xa++ - *xb++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = y & FFFFFFFF; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = y & FFFFFFFF; + } +#else +#ifdef Pack_32 + do { + y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } + while(xb < xbe); + while(xa < xae) { + y = (*xa & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } +#else + do { + y = *xa++ - *xb++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } +#endif +#endif + while(!*--xc) + wa--; + c->wds = wa; + return c; + } + + static double +ulp +#ifdef KR_headers + (x) U *x; +#else + (U *x) +#endif +{ + Long L; + U u; + + L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + if (L > 0) { +#endif +#endif +#ifdef IBM + L |= Exp_msk1 >> 4; +#endif + word0(&u) = L; + word1(&u) = 0; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + } + else { + L = -L >> Exp_shift; + if (L < Exp_shift) { + word0(&u) = 0x80000 >> L; + word1(&u) = 0; + } + else { + word0(&u) = 0; + L -= Exp_shift; + word1(&u) = L >= 31 ? 1 : 1 << 31 - L; + } + } +#endif +#endif + return dval(&u); + } + + static double +b2d +#ifdef KR_headers + (a, e) Bigint *a; int *e; +#else + (Bigint *a, int *e) +#endif +{ + ULong *xa, *xa0, w, y, z; + int k; + U d; +#ifdef VAX + ULong d0, d1; +#else +#define d0 word0(&d) +#define d1 word1(&d) +#endif + + xa0 = a->x; + xa = xa0 + a->wds; + y = *--xa; +#ifdef DEBUG + if (!y) Bug("zero y in b2d"); +#endif + k = hi0bits(y); + *e = 32 - k; +#ifdef Pack_32 + if (k < Ebits) { + d0 = Exp_1 | y >> (Ebits - k); + w = xa > xa0 ? *--xa : 0; + d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + if (k -= Ebits) { + d0 = Exp_1 | y << k | z >> (32 - k); + y = xa > xa0 ? *--xa : 0; + d1 = z << k | y >> (32 - k); + } + else { + d0 = Exp_1 | y; + d1 = z; + } +#else + if (k < Ebits + 16) { + z = xa > xa0 ? *--xa : 0; + d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; + w = xa > xa0 ? *--xa : 0; + y = xa > xa0 ? *--xa : 0; + d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + w = xa > xa0 ? *--xa : 0; + k -= Ebits + 16; + d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; + y = xa > xa0 ? *--xa : 0; + d1 = w << k + 16 | y << k; +#endif + ret_d: +#ifdef VAX + word0(&d) = d0 >> 16 | d0 << 16; + word1(&d) = d1 >> 16 | d1 << 16; +#else +#undef d0 +#undef d1 +#endif + return dval(&d); + } + + static Bigint * +d2b +#ifdef KR_headers + (d, e, bits) U *d; int *e, *bits; +#else + (U *d, int *e, int *bits) +#endif +{ + Bigint *b; + int de, k; + ULong *x, y, z; +#ifndef Sudden_Underflow + int i; +#endif +#ifdef VAX + ULong d0, d1; + d0 = word0(d) >> 16 | word0(d) << 16; + d1 = word1(d) >> 16 | word1(d) << 16; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + +#ifdef Pack_32 + b = Balloc(1); +#else + b = Balloc(2); +#endif + x = b->x; + + z = d0 & Frac_mask; + d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ +#ifdef Sudden_Underflow + de = (int)(d0 >> Exp_shift); +#ifndef IBM + z |= Exp_msk11; +#endif +#else + if ((de = (int)(d0 >> Exp_shift))) + z |= Exp_msk1; +#endif +#ifdef Pack_32 + if ((y = d1)) { + if ((k = lo0bits(&y))) { + x[0] = y | z << (32 - k); + z >>= k; + } + else + x[0] = y; +#ifndef Sudden_Underflow + i = +#endif + b->wds = (x[1] = z) ? 2 : 1; + } + else { + k = lo0bits(&z); + x[0] = z; +#ifndef Sudden_Underflow + i = +#endif + b->wds = 1; + k += 32; + } +#else + if (y = d1) { + if (k = lo0bits(&y)) + if (k >= 16) { + x[0] = y | z << 32 - k & 0xffff; + x[1] = z >> k - 16 & 0xffff; + x[2] = z >> k; + i = 2; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16 | z << 16 - k & 0xffff; + x[2] = z >> k & 0xffff; + x[3] = z >> k+16; + i = 3; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16; + x[2] = z & 0xffff; + x[3] = z >> 16; + i = 3; + } + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + if (k >= 16) { + x[0] = z; + i = 0; + } + else { + x[0] = z & 0xffff; + x[1] = z >> 16; + i = 1; + } + k += 32; + } + while(!x[i]) + --i; + b->wds = i + 1; +#endif +#ifndef Sudden_Underflow + if (de) { +#endif +#ifdef IBM + *e = (de - Bias - (P-1) << 2) + k; + *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); +#else + *e = de - Bias - (P-1) + k; + *bits = P - k; +#endif +#ifndef Sudden_Underflow + } + else { + *e = de - Bias - (P-1) + 1 + k; +#ifdef Pack_32 + *bits = 32*i - hi0bits(x[i-1]); +#else + *bits = (i+2)*16 - hi0bits(x[i]); +#endif + } +#endif + return b; + } +#undef d0 +#undef d1 + + static double +ratio +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + U da, db; + int k, ka, kb; + + dval(&da) = b2d(a, &ka); + dval(&db) = b2d(b, &kb); +#ifdef Pack_32 + k = ka - kb + 32*(a->wds - b->wds); +#else + k = ka - kb + 16*(a->wds - b->wds); +#endif +#ifdef IBM + if (k > 0) { + word0(&da) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(&da) *= 1 << k; + } + else { + k = -k; + word0(&db) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(&db) *= 1 << k; + } +#else + if (k > 0) + word0(&da) += k*Exp_msk1; + else { + k = -k; + word0(&db) += k*Exp_msk1; + } +#endif + return dval(&da) / dval(&db); + } + + static CONST double +tens[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 +#ifdef VAX + , 1e23, 1e24 +#endif + }; + + static CONST double +#ifdef IEEE_Arith +bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, +#ifdef Avoid_Underflow + 9007199254740992.*9007199254740992.e-256 + /* = 2^106 * 1e-256 */ +#else + 1e-256 +#endif + }; +/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ +/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ +#define Scale_Bit 0x10 +#define n_bigtens 5 +#else +#ifdef IBM +bigtens[] = { 1e16, 1e32, 1e64 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; +#define n_bigtens 3 +#else +bigtens[] = { 1e16, 1e32 }; +static CONST double tinytens[] = { 1e-16, 1e-32 }; +#define n_bigtens 2 +#endif +#endif + +#undef Need_Hexdig +#ifdef INFNAN_CHECK +#ifndef No_Hex_NaN +#define Need_Hexdig +#endif +#endif + +#ifndef Need_Hexdig +#ifndef NO_HEX_FP +#define Need_Hexdig +#endif +#endif + +#ifdef Need_Hexdig /*{*/ +static unsigned char hexdig[256]; + + static void +#ifdef KR_headers +htinit(h, s, inc) unsigned char *h; unsigned char *s; int inc; +#else +htinit(unsigned char *h, unsigned char *s, int inc) +#endif +{ + int i, j; + for(i = 0; (j = s[i]) !=0; i++) + h[j] = i + inc; + } + + static void +#ifdef KR_headers +hexdig_init() +#else +hexdig_init(void) +#endif +{ +#define USC (unsigned char *) + htinit(hexdig, USC "0123456789", 0x10); + htinit(hexdig, USC "abcdef", 0x10 + 10); + htinit(hexdig, USC "ABCDEF", 0x10 + 10); + } +#endif /* } Need_Hexdig */ + +#ifdef INFNAN_CHECK + +#ifndef NAN_WORD0 +#define NAN_WORD0 0x7ff80000 +#endif + +#ifndef NAN_WORD1 +#define NAN_WORD1 0 +#endif + + static int +match +#ifdef KR_headers + (sp, t) char **sp, *t; +#else + (const char **sp, const char *t) +#endif +{ + int c, d; + CONST char *s = *sp; + + while((d = *t++)) { + if ((c = *++s) >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c != d) + return 0; + } + *sp = s + 1; + return 1; + } + +#ifndef No_Hex_NaN + static void +hexnan +#ifdef KR_headers + (rvp, sp) U *rvp; CONST char **sp; +#else + (U *rvp, const char **sp) +#endif +{ + ULong c, x[2]; + CONST char *s; + int c1, havedig, udx0, xshift; + + if (!hexdig['0']) + hexdig_init(); + x[0] = x[1] = 0; + havedig = xshift = 0; + udx0 = 1; + s = *sp; + /* allow optional initial 0x or 0X */ + while((c = *(CONST unsigned char*)(s+1)) && c <= ' ') + ++s; + if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X')) + s += 2; + while((c = *(CONST unsigned char*)++s)) { + if ((c1 = hexdig[c])) + c = c1 & 0xf; + else if (c <= ' ') { + if (udx0 && havedig) { + udx0 = 0; + xshift = 1; + } + continue; + } +#ifdef GDTOA_NON_PEDANTIC_NANCHECK + else if (/*(*/ c == ')' && havedig) { + *sp = s + 1; + break; + } + else + return; /* invalid form: don't change *sp */ +#else + else { + do { + if (/*(*/ c == ')') { + *sp = s + 1; + break; + } + } while((c = *++s)); + break; + } +#endif + havedig = 1; + if (xshift) { + xshift = 0; + x[0] = x[1]; + x[1] = 0; + } + if (udx0) + x[0] = (x[0] << 4) | (x[1] >> 28); + x[1] = (x[1] << 4) | c; + } + if ((x[0] &= 0xfffff) || x[1]) { + word0(rvp) = Exp_mask | x[0]; + word1(rvp) = x[1]; + } + } +#endif /*No_Hex_NaN*/ +#endif /* INFNAN_CHECK */ + +#ifdef Pack_32 +#define ULbits 32 +#define kshift 5 +#define kmask 31 +#else +#define ULbits 16 +#define kshift 4 +#define kmask 15 +#endif + +#if !defined(NO_HEX_FP) || defined(Honor_FLT_ROUNDS) /*{*/ + static Bigint * +#ifdef KR_headers +increment(b) Bigint *b; +#else +increment(Bigint *b) +#endif +{ + ULong *x, *xe; + Bigint *b1; + + x = b->x; + xe = x + b->wds; + do { + if (*x < (ULong)0xffffffffL) { + ++*x; + return b; + } + *x++ = 0; + } while(x < xe); + { + if (b->wds >= b->maxwds) { + b1 = Balloc(b->k+1); + Bcopy(b1,b); + Bfree(b); + b = b1; + } + b->x[b->wds++] = 1; + } + return b; + } + +#endif /*}*/ + +#ifndef NO_HEX_FP /*{*/ + + static void +#ifdef KR_headers +rshift(b, k) Bigint *b; int k; +#else +rshift(Bigint *b, int k) +#endif +{ + ULong *x, *x1, *xe, y; + int n; + + x = x1 = b->x; + n = k >> kshift; + if (n < b->wds) { + xe = x + b->wds; + x += n; + if (k &= kmask) { + n = 32 - k; + y = *x++ >> k; + while(x < xe) { + *x1++ = (y | (*x << n)) & 0xffffffff; + y = *x++ >> k; + } + if ((*x1 = y) !=0) + x1++; + } + else + while(x < xe) + *x1++ = *x++; + } + if ((b->wds = x1 - b->x) == 0) + b->x[0] = 0; + } + + static ULong +#ifdef KR_headers +any_on(b, k) Bigint *b; int k; +#else +any_on(Bigint *b, int k) +#endif +{ + int n, nwds; + ULong *x, *x0, x1, x2; + + x = b->x; + nwds = b->wds; + n = k >> kshift; + if (n > nwds) + n = nwds; + else if (n < nwds && (k &= kmask)) { + x1 = x2 = x[n]; + x1 >>= k; + x1 <<= k; + if (x1 != x2) + return 1; + } + x0 = x; + x += n; + while(x > x0) + if (*--x) + return 1; + return 0; + } + +enum { /* rounding values: same as FLT_ROUNDS */ + Round_zero = 0, + Round_near = 1, + Round_up = 2, + Round_down = 3 + }; + + void +#ifdef KR_headers +gethex(sp, rvp, rounding, sign) + CONST char **sp; U *rvp; int rounding, sign; +#else +gethex( CONST char **sp, U *rvp, int rounding, int sign) +#endif +{ + Bigint *b; + CONST unsigned char *decpt, *s0, *s, *s1; + Long e, e1; + ULong L, lostbits, *x; + int big, denorm, esign, havedig, k, n, nbits, up, zret; +#ifdef IBM + int j; +#endif + enum { +#ifdef IEEE_Arith /*{{*/ + emax = 0x7fe - Bias - P + 1, + emin = Emin - P + 1 +#else /*}{*/ + emin = Emin - P, +#ifdef VAX + emax = 0x7ff - Bias - P + 1 +#endif +#ifdef IBM + emax = 0x7f - Bias - P +#endif +#endif /*}}*/ + }; +#ifdef USE_LOCALE + int i; +#ifdef NO_LOCALE_CACHE + const unsigned char *decimalpoint = (unsigned char*) + localeconv()->decimal_point; +#else + const unsigned char *decimalpoint; + static unsigned char *decimalpoint_cache; + if (!(s0 = decimalpoint_cache)) { + s0 = (unsigned char*)localeconv()->decimal_point; + if ((decimalpoint_cache = (unsigned char*) + MALLOC(strlen((CONST char*)s0) + 1))) { + strcpy((char*)decimalpoint_cache, (CONST char*)s0); + s0 = decimalpoint_cache; + } + } + decimalpoint = s0; +#endif +#endif + + if (!hexdig['0']) + hexdig_init(); + havedig = 0; + s0 = *(CONST unsigned char **)sp + 2; + while(s0[havedig] == '0') + havedig++; + s0 += havedig; + s = s0; + decpt = 0; + zret = 0; + e = 0; + if (hexdig[*s]) + havedig++; + else { + zret = 1; +#ifdef USE_LOCALE + for(i = 0; decimalpoint[i]; ++i) { + if (s[i] != decimalpoint[i]) + goto pcheck; + } + decpt = s += i; +#else + if (*s != '.') + goto pcheck; + decpt = ++s; +#endif + if (!hexdig[*s]) + goto pcheck; + while(*s == '0') + s++; + if (hexdig[*s]) + zret = 0; + havedig = 1; + s0 = s; + } + while(hexdig[*s]) + s++; +#ifdef USE_LOCALE + if (*s == *decimalpoint && !decpt) { + for(i = 1; decimalpoint[i]; ++i) { + if (s[i] != decimalpoint[i]) + goto pcheck; + } + decpt = s += i; +#else + if (*s == '.' && !decpt) { + decpt = ++s; +#endif + while(hexdig[*s]) + s++; + }/*}*/ + if (decpt) + e = -(((Long)(s-decpt)) << 2); + pcheck: + s1 = s; + big = esign = 0; + switch(*s) { + case 'p': + case 'P': + switch(*++s) { + case '-': + esign = 1; + /* no break */ + case '+': + s++; + } + if ((n = hexdig[*s]) == 0 || n > 0x19) { + s = s1; + break; + } + e1 = n - 0x10; + while((n = hexdig[*++s]) !=0 && n <= 0x19) { + if (e1 & 0xf8000000) + big = 1; + e1 = 10*e1 + n - 0x10; + } + if (esign) + e1 = -e1; + e += e1; + } + *sp = (char*)s; + if (!havedig) + *sp = (char*)s0 - 1; + if (zret) + goto retz1; + if (big) { + if (esign) { +#ifdef IEEE_Arith + switch(rounding) { + case Round_up: + if (sign) + break; + goto ret_tiny; + case Round_down: + if (!sign) + break; + goto ret_tiny; + } +#endif + goto retz; +#ifdef IEEE_Arith + ret_tiny: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + word0(rvp) = 0; + word1(rvp) = 1; + return; +#endif /* IEEE_Arith */ + } + switch(rounding) { + case Round_near: + goto ovfl1; + case Round_up: + if (!sign) + goto ovfl1; + goto ret_big; + case Round_down: + if (sign) + goto ovfl1; + goto ret_big; + } + ret_big: + word0(rvp) = Big0; + word1(rvp) = Big1; + return; + } + n = s1 - s0 - 1; + for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) + k++; + b = Balloc(k); + x = b->x; + n = 0; + L = 0; +#ifdef USE_LOCALE + for(i = 0; decimalpoint[i+1]; ++i); +#endif + while(s1 > s0) { +#ifdef USE_LOCALE + if (*--s1 == decimalpoint[i]) { + s1 -= i; + continue; + } +#else + if (*--s1 == '.') + continue; +#endif + if (n == ULbits) { + *x++ = L; + L = 0; + n = 0; + } + L |= (hexdig[*s1] & 0x0f) << n; + n += 4; + } + *x++ = L; + b->wds = n = x - b->x; + n = ULbits*n - hi0bits(L); + nbits = Nbits; + lostbits = 0; + x = b->x; + if (n > nbits) { + n -= nbits; + if (any_on(b,n)) { + lostbits = 1; + k = n - 1; + if (x[k>>kshift] & 1 << (k & kmask)) { + lostbits = 2; + if (k > 0 && any_on(b,k)) + lostbits = 3; + } + } + rshift(b, n); + e += n; + } + else if (n < nbits) { + n = nbits - n; + b = lshift(b, n); + e -= n; + x = b->x; + } + if (e > Emax) { + ovfl: + Bfree(b); + ovfl1: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + word0(rvp) = Exp_mask; + word1(rvp) = 0; + return; + } + denorm = 0; + if (e < emin) { + denorm = 1; + n = emin - e; + if (n >= nbits) { +#ifdef IEEE_Arith /*{*/ + switch (rounding) { + case Round_near: + if (n == nbits && (n < 2 || any_on(b,n-1))) + goto ret_tiny; + break; + case Round_up: + if (!sign) + goto ret_tiny; + break; + case Round_down: + if (sign) + goto ret_tiny; + } +#endif /* } IEEE_Arith */ + Bfree(b); + retz: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + retz1: + rvp->d = 0.; + return; + } + k = n - 1; + if (lostbits) + lostbits = 1; + else if (k > 0) + lostbits = any_on(b,k); + if (x[k>>kshift] & 1 << (k & kmask)) + lostbits |= 2; + nbits -= n; + rshift(b,n); + e = emin; + } + if (lostbits) { + up = 0; + switch(rounding) { + case Round_zero: + break; + case Round_near: + if (lostbits & 2 + && (lostbits & 1) | (x[0] & 1)) + up = 1; + break; + case Round_up: + up = 1 - sign; + break; + case Round_down: + up = sign; + } + if (up) { + k = b->wds; + b = increment(b); + x = b->x; + if (denorm) { +#if 0 + if (nbits == Nbits - 1 + && x[nbits >> kshift] & 1 << (nbits & kmask)) + denorm = 0; /* not currently used */ +#endif + } + else if (b->wds > k + || ((n = nbits & kmask) !=0 + && hi0bits(x[k-1]) < 32-n)) { + rshift(b,1); + if (++e > Emax) + goto ovfl; + } + } + } +#ifdef IEEE_Arith + if (denorm) + word0(rvp) = b->wds > 1 ? b->x[1] & ~0x100000 : 0; + else + word0(rvp) = (b->x[1] & ~0x100000) | ((e + 0x3ff + 52) << 20); + word1(rvp) = b->x[0]; +#endif +#ifdef IBM + if ((j = e & 3)) { + k = b->x[0] & ((1 << j) - 1); + rshift(b,j); + if (k) { + switch(rounding) { + case Round_up: + if (!sign) + increment(b); + break; + case Round_down: + if (sign) + increment(b); + break; + case Round_near: + j = 1 << (j-1); + if (k & j && ((k & (j-1)) | lostbits)) + increment(b); + } + } + } + e >>= 2; + word0(rvp) = b->x[1] | ((e + 65 + 13) << 24); + word1(rvp) = b->x[0]; +#endif +#ifdef VAX + /* The next two lines ignore swap of low- and high-order 2 bytes. */ + /* word0(rvp) = (b->x[1] & ~0x800000) | ((e + 129 + 55) << 23); */ + /* word1(rvp) = b->x[0]; */ + word0(rvp) = ((b->x[1] & ~0x800000) >> 16) | ((e + 129 + 55) << 7) | (b->x[1] << 16); + word1(rvp) = (b->x[0] >> 16) | (b->x[0] << 16); +#endif + Bfree(b); + } +#endif /*!NO_HEX_FP}*/ + + static int +#ifdef KR_headers +dshift(b, p2) Bigint *b; int p2; +#else +dshift(Bigint *b, int p2) +#endif +{ + int rv = hi0bits(b->x[b->wds-1]) - 4; + if (p2 > 0) + rv -= p2; + return rv & kmask; + } + + static int +quorem +#ifdef KR_headers + (b, S) Bigint *b, *S; +#else + (Bigint *b, Bigint *S) +#endif +{ + int n; + ULong *bx, *bxe, q, *sx, *sxe; +#ifdef ULLong + ULLong borrow, carry, y, ys; +#else + ULong borrow, carry, y, ys; +#ifdef Pack_32 + ULong si, z, zs; +#endif +#endif + + n = S->wds; +#ifdef DEBUG + /*debug*/ if (b->wds > n) + /*debug*/ Bug("oversize b in quorem"); +#endif + if (b->wds < n) + return 0; + sx = S->x; + sxe = sx + --n; + bx = b->x; + bxe = bx + n; + q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ +#ifdef DEBUG +#ifdef NO_STRTOD_BIGCOMP + /*debug*/ if (q > 9) +#else + /* An oversized q is possible when quorem is called from bigcomp and */ + /* the input is near, e.g., twice the smallest denormalized number. */ + /*debug*/ if (q > 15) +#endif + /*debug*/ Bug("oversized quotient in quorem"); +#endif + if (q) { + borrow = 0; + carry = 0; + do { +#ifdef ULLong + ys = *sx++ * (ULLong)q + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) * q + carry; + zs = (si >> 16) * q + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ * q + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + if (!*bxe) { + bx = b->x; + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + if (cmp(b, S) >= 0) { + q++; + borrow = 0; + carry = 0; + bx = b->x; + sx = S->x; + do { +#ifdef ULLong + ys = *sx++ + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) + carry; + zs = (si >> 16) + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + bx = b->x; + bxe = bx + n; + if (!*bxe) { + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + return q; + } + +#if defined(Avoid_Underflow) || !defined(NO_STRTOD_BIGCOMP) /*{*/ + static double +sulp +#ifdef KR_headers + (x, bc) U *x; BCinfo *bc; +#else + (U *x, BCinfo *bc) +#endif +{ + U u; + double rv; + int i; + + rv = ulp(x); + if (!bc->scale || (i = 2*P + 1 - ((word0(x) & Exp_mask) >> Exp_shift)) <= 0) + return rv; /* Is there an example where i <= 0 ? */ + word0(&u) = Exp_1 + (i << Exp_shift); + word1(&u) = 0; + return rv * u.d; + } +#endif /*}*/ + +#ifndef NO_STRTOD_BIGCOMP + static void +bigcomp +#ifdef KR_headers + (rv, s0, bc) + U *rv; CONST char *s0; BCinfo *bc; +#else + (U *rv, const char *s0, BCinfo *bc) +#endif +{ + Bigint *b, *d; + int b2, bbits, d2, dd, dig, dsign, i, j, nd, nd0, p2, p5, speccase; + + dsign = bc->dsign; + nd = bc->nd; + nd0 = bc->nd0; + p5 = nd + bc->e0 - 1; + speccase = 0; +#ifndef Sudden_Underflow + if (rv->d == 0.) { /* special case: value near underflow-to-zero */ + /* threshold was rounded to zero */ + b = i2b(1); + p2 = Emin - P + 1; + bbits = 1; +#ifdef Avoid_Underflow + word0(rv) = (P+2) << Exp_shift; +#else + word1(rv) = 1; +#endif + i = 0; +#ifdef Honor_FLT_ROUNDS + if (bc->rounding == 1) +#endif + { + speccase = 1; + --p2; + dsign = 0; + goto have_i; + } + } + else +#endif + b = d2b(rv, &p2, &bbits); +#ifdef Avoid_Underflow + p2 -= bc->scale; +#endif + /* floor(log2(rv)) == bbits - 1 + p2 */ + /* Check for denormal case. */ + i = P - bbits; + if (i > (j = P - Emin - 1 + p2)) { +#ifdef Sudden_Underflow + Bfree(b); + b = i2b(1); + p2 = Emin; + i = P - 1; +#ifdef Avoid_Underflow + word0(rv) = (1 + bc->scale) << Exp_shift; +#else + word0(rv) = Exp_msk1; +#endif + word1(rv) = 0; +#else + i = j; +#endif + } +#ifdef Honor_FLT_ROUNDS + if (bc->rounding != 1) { + if (i > 0) + b = lshift(b, i); + if (dsign) + b = increment(b); + } + else +#endif + { + b = lshift(b, ++i); + b->x[0] |= 1; + } +#ifndef Sudden_Underflow + have_i: +#endif + p2 -= p5 + i; + d = i2b(1); + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + */ + if (p5 > 0) + d = pow5mult(d, p5); + else if (p5 < 0) + b = pow5mult(b, -p5); + if (p2 > 0) { + b2 = p2; + d2 = 0; + } + else { + b2 = 0; + d2 = -p2; + } + i = dshift(d, d2); + if ((b2 += i) > 0) + b = lshift(b, b2); + if ((d2 += i) > 0) + d = lshift(d, d2); + + /* Now b/d = exactly half-way between the two floating-point values */ + /* on either side of the input string. Compute first digit of b/d. */ + + if (!(dig = quorem(b,d))) { + b = multadd(b, 10, 0); /* very unlikely */ + dig = quorem(b,d); + } + + /* Compare b/d with s0 */ + + for(i = 0; i < nd0; ) { + if ((dd = s0[i++] - '0' - dig)) + goto ret; + if (!b->x[0] && b->wds == 1) { + if (i < nd) + dd = 1; + goto ret; + } + b = multadd(b, 10, 0); + dig = quorem(b,d); + } + for(j = bc->dp1; i++ < nd;) { + if ((dd = s0[j++] - '0' - dig)) + goto ret; + if (!b->x[0] && b->wds == 1) { + if (i < nd) + dd = 1; + goto ret; + } + b = multadd(b, 10, 0); + dig = quorem(b,d); + } + if (dig > 0 || b->x[0] || b->wds > 1) + dd = -1; + ret: + Bfree(b); + Bfree(d); +#ifdef Honor_FLT_ROUNDS + if (bc->rounding != 1) { + if (dd < 0) { + if (bc->rounding == 0) { + if (!dsign) + goto retlow1; + } + else if (dsign) + goto rethi1; + } + else if (dd > 0) { + if (bc->rounding == 0) { + if (dsign) + goto rethi1; + goto ret1; + } + if (!dsign) + goto rethi1; + dval(rv) += 2.*sulp(rv,bc); + } + else { + bc->inexact = 0; + if (dsign) + goto rethi1; + } + } + else +#endif + if (speccase) { + if (dd <= 0) + rv->d = 0.; + } + else if (dd < 0) { + if (!dsign) /* does not happen for round-near */ +retlow1: + dval(rv) -= sulp(rv,bc); + } + else if (dd > 0) { + if (dsign) { + rethi1: + dval(rv) += sulp(rv,bc); + } + } + else { + /* Exact half-way case: apply round-even rule. */ + if ((j = ((word0(rv) & Exp_mask) >> Exp_shift) - bc->scale) <= 0) { + i = 1 - j; + if (i <= 31) { + if (word1(rv) & (0x1 << i)) + goto odd; + } + else if (word0(rv) & (0x1 << (i-32))) + goto odd; + } + else if (word1(rv) & 1) { + odd: + if (dsign) + goto rethi1; + goto retlow1; + } + } + +#ifdef Honor_FLT_ROUNDS + ret1: +#endif + return; + } +#endif /* NO_STRTOD_BIGCOMP */ + + double +strtod +#ifdef KR_headers + (s00, se) CONST char *s00; char **se; +#else + (const char *s00, char **se) +#endif +{ + int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1; + int esign, i, j, k, nd, nd0, nf, nz, nz0, nz1, sign; + CONST char *s, *s0, *s1; + double aadj, aadj1; + Long L; + U aadj2, adj, rv, rv0; + ULong y, z; + BCinfo bc; + Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; +#ifdef Avoid_Underflow + ULong Lsb, Lsb1; +#endif +#ifdef SET_INEXACT + int oldinexact; +#endif +#ifndef NO_STRTOD_BIGCOMP + int req_bigcomp = 0; +#endif +#ifdef Honor_FLT_ROUNDS /*{*/ +#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ + bc.rounding = Flt_Rounds; +#else /*}{*/ + bc.rounding = 1; + switch(fegetround()) { + case FE_TOWARDZERO: bc.rounding = 0; break; + case FE_UPWARD: bc.rounding = 2; break; + case FE_DOWNWARD: bc.rounding = 3; + } +#endif /*}}*/ +#endif /*}*/ +#ifdef USE_LOCALE + CONST char *s2; +#endif + + sign = nz0 = nz1 = nz = bc.dplen = bc.uflchk = 0; + dval(&rv) = 0.; + for(s = s00;;s++) switch(*s) { + case '-': + sign = 1; + /* no break */ + case '+': + if (*++s) + goto break2; + /* no break */ + case 0: + goto ret0; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; + default: + goto break2; + } + break2: + if (*s == '0') { +#ifndef NO_HEX_FP /*{*/ + switch(s[1]) { + case 'x': + case 'X': +#ifdef Honor_FLT_ROUNDS + gethex(&s, &rv, bc.rounding, sign); +#else + gethex(&s, &rv, 1, sign); +#endif + goto ret; + } +#endif /*}*/ + nz0 = 1; + while(*++s == '0') ; + if (!*s) + goto ret; + } + s0 = s; + y = z = 0; + for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) + if (nd < 9) + y = 10*y + c - '0'; + else if (nd < 16) + z = 10*z + c - '0'; + nd0 = nd; + bc.dp0 = bc.dp1 = s - s0; + for(s1 = s; s1 > s0 && *--s1 == '0'; ) + ++nz1; +#ifdef USE_LOCALE + s1 = localeconv()->decimal_point; + if (c == *s1) { + c = '.'; + if (*++s1) { + s2 = s; + for(;;) { + if (*++s2 != *s1) { + c = 0; + break; + } + if (!*++s1) { + s = s2; + break; + } + } + } + } +#endif + if (c == '.') { + c = *++s; + bc.dp1 = s - s0; + bc.dplen = bc.dp1 - bc.dp0; + if (!nd) { + for(; c == '0'; c = *++s) + nz++; + if (c > '0' && c <= '9') { + bc.dp0 = s0 - s; + bc.dp1 = bc.dp0 + bc.dplen; + s0 = s; + nf += nz; + nz = 0; + goto have_dig; + } + goto dig_done; + } + for(; c >= '0' && c <= '9'; c = *++s) { + have_dig: + nz++; + if (c -= '0') { + nf += nz; + for(i = 1; i < nz; i++) + if (nd++ < 9) + y *= 10; + else if (nd <= DBL_DIG + 1) + z *= 10; + if (nd++ < 9) + y = 10*y + c; + else if (nd <= DBL_DIG + 1) + z = 10*z + c; + nz = nz1 = 0; + } + } + } + dig_done: + e = 0; + if (c == 'e' || c == 'E') { + if (!nd && !nz && !nz0) { + goto ret0; + } + s00 = s; + esign = 0; + switch(c = *++s) { + case '-': + esign = 1; + case '+': + c = *++s; + } + if (c >= '0' && c <= '9') { + while(c == '0') + c = *++s; + if (c > '0' && c <= '9') { + L = c - '0'; + s1 = s; + while((c = *++s) >= '0' && c <= '9') + L = 10*L + c - '0'; + if (s - s1 > 8 || L > 19999) + /* Avoid confusion from exponents + * so large that e might overflow. + */ + e = 19999; /* safe for 16 bit ints */ + else + e = (int)L; + if (esign) + e = -e; + } + else + e = 0; + } + else + s = s00; + } + if (!nd) { + if (!nz && !nz0) { +#ifdef INFNAN_CHECK + /* Check for Nan and Infinity */ + if (!bc.dplen) + switch(c) { + case 'i': + case 'I': + if (match(&s,"nf")) { + --s; + if (!match(&s,"inity")) + ++s; + word0(&rv) = 0x7ff00000; + word1(&rv) = 0; + goto ret; + } + break; + case 'n': + case 'N': + if (match(&s, "an")) { + word0(&rv) = NAN_WORD0; + word1(&rv) = NAN_WORD1; +#ifndef No_Hex_NaN + if (*s == '(') /*)*/ + hexnan(&rv, &s); +#endif + goto ret; + } + } +#endif /* INFNAN_CHECK */ + ret0: + s = s00; + sign = 0; + } + goto ret; + } + bc.e0 = e1 = e -= nf; + + /* Now we have nd0 digits, starting at s0, followed by a + * decimal point, followed by nd-nd0 digits. The number we're + * after is the integer represented by those digits times + * 10**e */ + + if (!nd0) + nd0 = nd; + k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; + dval(&rv) = y; + if (k > 9) { +#ifdef SET_INEXACT + if (k > DBL_DIG) + oldinexact = get_inexact(); +#endif + dval(&rv) = tens[k - 9] * dval(&rv) + z; + } + bd0 = 0; + if (nd <= DBL_DIG +#ifndef RND_PRODQUOT +#ifndef Honor_FLT_ROUNDS + && Flt_Rounds == 1 +#endif +#endif + ) { + if (!e) + goto ret; +#ifndef ROUND_BIASED_without_Round_Up + if (e > 0) { + if (e <= Ten_pmax) { +#ifdef VAX + goto vax_ovfl_check; +#else +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv.d = -rv.d; + sign = 0; + } +#endif + /* rv = */ rounded_product(dval(&rv), tens[e]); + goto ret; +#endif + } + i = DBL_DIG - nd; + if (e <= Ten_pmax + i) { + /* A fancier test would sometimes let us do + * this for larger i values. + */ +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv.d = -rv.d; + sign = 0; + } +#endif + e -= i; + dval(&rv) *= tens[i]; +#ifdef VAX + /* VAX exponent range is so narrow we must + * worry about overflow here... + */ + vax_ovfl_check: + word0(&rv) -= P*Exp_msk1; + /* rv = */ rounded_product(dval(&rv), tens[e]); + if ((word0(&rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) + goto ovfl; + word0(&rv) += P*Exp_msk1; +#else + /* rv = */ rounded_product(dval(&rv), tens[e]); +#endif + goto ret; + } + } +#ifndef Inaccurate_Divide + else if (e >= -Ten_pmax) { +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv.d = -rv.d; + sign = 0; + } +#endif + /* rv = */ rounded_quotient(dval(&rv), tens[-e]); + goto ret; + } +#endif +#endif /* ROUND_BIASED_without_Round_Up */ + } + e1 += nd - k; + +#ifdef IEEE_Arith +#ifdef SET_INEXACT + bc.inexact = 1; + if (k <= DBL_DIG) + oldinexact = get_inexact(); +#endif +#ifdef Avoid_Underflow + bc.scale = 0; +#endif +#ifdef Honor_FLT_ROUNDS + if (bc.rounding >= 2) { + if (sign) + bc.rounding = bc.rounding == 2 ? 0 : 2; + else + if (bc.rounding != 2) + bc.rounding = 0; + } +#endif +#endif /*IEEE_Arith*/ + + /* Get starting approximation = rv * 10**e1 */ + + if (e1 > 0) { + if ((i = e1 & 15)) + dval(&rv) *= tens[i]; + if (e1 &= ~15) { + if (e1 > DBL_MAX_10_EXP) { + ovfl: + /* Can't trust HUGE_VAL */ +#ifdef IEEE_Arith +#ifdef Honor_FLT_ROUNDS + switch(bc.rounding) { + case 0: /* toward 0 */ + case 3: /* toward -infinity */ + word0(&rv) = Big0; + word1(&rv) = Big1; + break; + default: + word0(&rv) = Exp_mask; + word1(&rv) = 0; + } +#else /*Honor_FLT_ROUNDS*/ + word0(&rv) = Exp_mask; + word1(&rv) = 0; +#endif /*Honor_FLT_ROUNDS*/ +#ifdef SET_INEXACT + /* set overflow bit */ + dval(&rv0) = 1e300; + dval(&rv0) *= dval(&rv0); +#endif +#else /*IEEE_Arith*/ + word0(&rv) = Big0; + word1(&rv) = Big1; +#endif /*IEEE_Arith*/ + range_err: + if (bd0) { + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); + } +#ifndef NO_ERRNO + errno = ERANGE; +#endif + goto ret; + } + e1 >>= 4; + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(&rv) *= bigtens[j]; + /* The last multiplication could overflow. */ + word0(&rv) -= P*Exp_msk1; + dval(&rv) *= bigtens[j]; + if ((z = word0(&rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + /* set to largest number */ + /* (Can't trust DBL_MAX) */ + word0(&rv) = Big0; + word1(&rv) = Big1; + } + else + word0(&rv) += P*Exp_msk1; + } + } + else if (e1 < 0) { + e1 = -e1; + if ((i = e1 & 15)) + dval(&rv) /= tens[i]; + if (e1 >>= 4) { + if (e1 >= 1 << n_bigtens) + goto undfl; +#ifdef Avoid_Underflow + if (e1 & Scale_Bit) + bc.scale = 2*P; + for(j = 0; e1 > 0; j++, e1 >>= 1) + if (e1 & 1) + dval(&rv) *= tinytens[j]; + if (bc.scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask) + >> Exp_shift)) > 0) { + /* scaled rv is denormal; clear j low bits */ + if (j >= 32) { + if (j > 54) + goto undfl; + word1(&rv) = 0; + if (j >= 53) + word0(&rv) = (P+2)*Exp_msk1; + else + word0(&rv) &= 0xffffffff << (j-32); + } + else + word1(&rv) &= 0xffffffff << j; + } +#else + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(&rv) *= tinytens[j]; + /* The last multiplication could underflow. */ + dval(&rv0) = dval(&rv); + dval(&rv) *= tinytens[j]; + if (!dval(&rv)) { + dval(&rv) = 2.*dval(&rv0); + dval(&rv) *= tinytens[j]; +#endif + if (!dval(&rv)) { + undfl: + dval(&rv) = 0.; + goto range_err; + } +#ifndef Avoid_Underflow + word0(&rv) = Tiny0; + word1(&rv) = Tiny1; + /* The refinement below will clean + * this approximation up. + */ + } +#endif + } + } + + /* Now the hard part -- adjusting rv to the correct value.*/ + + /* Put digits into bd: true value = bd * 10^e */ + + bc.nd = nd - nz1; +#ifndef NO_STRTOD_BIGCOMP + bc.nd0 = nd0; /* Only needed if nd > strtod_diglim, but done here */ + /* to silence an erroneous warning about bc.nd0 */ + /* possibly not being initialized. */ + if (nd > strtod_diglim) { + /* ASSERT(strtod_diglim >= 18); 18 == one more than the */ + /* minimum number of decimal digits to distinguish double values */ + /* in IEEE arithmetic. */ + i = j = 18; + if (i > nd0) + j += bc.dplen; + for(;;) { + if (--j < bc.dp1 && j >= bc.dp0) + j = bc.dp0 - 1; + if (s0[j] != '0') + break; + --i; + } + e += nd - i; + nd = i; + if (nd0 > nd) + nd0 = nd; + if (nd < 9) { /* must recompute y */ + y = 0; + for(i = 0; i < nd0; ++i) + y = 10*y + s0[i] - '0'; + for(j = bc.dp1; i < nd; ++i) + y = 10*y + s0[j++] - '0'; + } + } +#endif + bd0 = s2b(s0, nd0, nd, y, bc.dplen); + + for(;;) { + bd = Balloc(bd0->k); + Bcopy(bd, bd0); + bb = d2b(&rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ + bs = i2b(1); + + if (e >= 0) { + bb2 = bb5 = 0; + bd2 = bd5 = e; + } + else { + bb2 = bb5 = -e; + bd2 = bd5 = 0; + } + if (bbe >= 0) + bb2 += bbe; + else + bd2 -= bbe; + bs2 = bb2; +#ifdef Honor_FLT_ROUNDS + if (bc.rounding != 1) + bs2++; +#endif +#ifdef Avoid_Underflow + Lsb = LSB; + Lsb1 = 0; + j = bbe - bc.scale; + i = j + bbbits - 1; /* logb(rv) */ + j = P + 1 - bbbits; + if (i < Emin) { /* denormal */ + i = Emin - i; + j -= i; + if (i < 32) + Lsb <<= i; + else if (i < 52) + Lsb1 = Lsb << (i-32); + else + Lsb1 = Exp_mask; + } +#else /*Avoid_Underflow*/ +#ifdef Sudden_Underflow +#ifdef IBM + j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); +#else + j = P + 1 - bbbits; +#endif +#else /*Sudden_Underflow*/ + j = bbe; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + bb2 += j; + bd2 += j; +#ifdef Avoid_Underflow + bd2 += bc.scale; +#endif + i = bb2 < bd2 ? bb2 : bd2; + if (i > bs2) + i = bs2; + if (i > 0) { + bb2 -= i; + bd2 -= i; + bs2 -= i; + } + if (bb5 > 0) { + bs = pow5mult(bs, bb5); + bb1 = mult(bs, bb); + Bfree(bb); + bb = bb1; + } + if (bb2 > 0) + bb = lshift(bb, bb2); + if (bd5 > 0) + bd = pow5mult(bd, bd5); + if (bd2 > 0) + bd = lshift(bd, bd2); + if (bs2 > 0) + bs = lshift(bs, bs2); + delta = diff(bb, bd); + bc.dsign = delta->sign; + delta->sign = 0; + i = cmp(delta, bs); +#ifndef NO_STRTOD_BIGCOMP /*{*/ + if (bc.nd > nd && i <= 0) { + if (bc.dsign) { + /* Must use bigcomp(). */ + req_bigcomp = 1; + break; + } +#ifdef Honor_FLT_ROUNDS + if (bc.rounding != 1) { + if (i < 0) { + req_bigcomp = 1; + break; + } + } + else +#endif + i = -1; /* Discarded digits make delta smaller. */ + } +#endif /*}*/ +#ifdef Honor_FLT_ROUNDS /*{*/ + if (bc.rounding != 1) { + if (i < 0) { + /* Error is less than an ulp */ + if (!delta->x[0] && delta->wds <= 1) { + /* exact */ +#ifdef SET_INEXACT + bc.inexact = 0; +#endif + break; + } + if (bc.rounding) { + if (bc.dsign) { + adj.d = 1.; + goto apply_adj; + } + } + else if (!bc.dsign) { + adj.d = -1.; + if (!word1(&rv) + && !(word0(&rv) & Frac_mask)) { + y = word0(&rv) & Exp_mask; +#ifdef Avoid_Underflow + if (!bc.scale || y > 2*P*Exp_msk1) +#else + if (y) +#endif + { + delta = lshift(delta,Log2P); + if (cmp(delta, bs) <= 0) + adj.d = -0.5; + } + } + apply_adj: +#ifdef Avoid_Underflow /*{*/ + if (bc.scale && (y = word0(&rv) & Exp_mask) + <= 2*P*Exp_msk1) + word0(&adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(&rv) & Exp_mask) <= + P*Exp_msk1) { + word0(&rv) += P*Exp_msk1; + dval(&rv) += adj.d*ulp(dval(&rv)); + word0(&rv) -= P*Exp_msk1; + } + else +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow}*/ + dval(&rv) += adj.d*ulp(&rv); + } + break; + } + adj.d = ratio(delta, bs); + if (adj.d < 1.) + adj.d = 1.; + if (adj.d <= 0x7ffffffe) { + /* adj = rounding ? ceil(adj) : floor(adj); */ + y = adj.d; + if (y != adj.d) { + if (!((bc.rounding>>1) ^ bc.dsign)) + y++; + adj.d = y; + } + } +#ifdef Avoid_Underflow /*{*/ + if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) + word0(&adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { + word0(&rv) += P*Exp_msk1; + adj.d *= ulp(dval(&rv)); + if (bc.dsign) + dval(&rv) += adj.d; + else + dval(&rv) -= adj.d; + word0(&rv) -= P*Exp_msk1; + goto cont; + } +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow}*/ + adj.d *= ulp(&rv); + if (bc.dsign) { + if (word0(&rv) == Big0 && word1(&rv) == Big1) + goto ovfl; + dval(&rv) += adj.d; + } + else + dval(&rv) -= adj.d; + goto cont; + } +#endif /*}Honor_FLT_ROUNDS*/ + + if (i < 0) { + /* Error is less than half an ulp -- check for + * special case of mantissa a power of two. + */ + if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask +#ifdef IEEE_Arith /*{*/ +#ifdef Avoid_Underflow + || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1 +#else + || (word0(&rv) & Exp_mask) <= Exp_msk1 +#endif +#endif /*}*/ + ) { +#ifdef SET_INEXACT + if (!delta->x[0] && delta->wds <= 1) + bc.inexact = 0; +#endif + break; + } + if (!delta->x[0] && delta->wds <= 1) { + /* exact result */ +#ifdef SET_INEXACT + bc.inexact = 0; +#endif + break; + } + delta = lshift(delta,Log2P); + if (cmp(delta, bs) > 0) + goto drop_down; + break; + } + if (i == 0) { + /* exactly half-way between */ + if (bc.dsign) { + if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 + && word1(&rv) == ( +#ifdef Avoid_Underflow + (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) + ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : +#endif + 0xffffffff)) { + /*boundary case -- increment exponent*/ + if (word0(&rv) == Big0 && word1(&rv) == Big1) + goto ovfl; + word0(&rv) = (word0(&rv) & Exp_mask) + + Exp_msk1 +#ifdef IBM + | Exp_msk1 >> 4 +#endif + ; + word1(&rv) = 0; +#ifdef Avoid_Underflow + bc.dsign = 0; +#endif + break; + } + } + else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { + drop_down: + /* boundary case -- decrement exponent */ +#ifdef Sudden_Underflow /*{{*/ + L = word0(&rv) & Exp_mask; +#ifdef IBM + if (L < Exp_msk1) +#else +#ifdef Avoid_Underflow + if (L <= (bc.scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) +#else + if (L <= Exp_msk1) +#endif /*Avoid_Underflow*/ +#endif /*IBM*/ + { + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } + L -= Exp_msk1; +#else /*Sudden_Underflow}{*/ +#ifdef Avoid_Underflow + if (bc.scale) { + L = word0(&rv) & Exp_mask; + if (L <= (2*P+1)*Exp_msk1) { + if (L > (P+2)*Exp_msk1) + /* round even ==> */ + /* accept rv */ + break; + /* rv = smallest denormal */ + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } + } +#endif /*Avoid_Underflow*/ + L = (word0(&rv) & Exp_mask) - Exp_msk1; +#endif /*Sudden_Underflow}}*/ + word0(&rv) = L | Bndry_mask1; + word1(&rv) = 0xffffffff; +#ifdef IBM + goto cont; +#else +#ifndef NO_STRTOD_BIGCOMP + if (bc.nd > nd) + goto cont; +#endif + break; +#endif + } +#ifndef ROUND_BIASED +#ifdef Avoid_Underflow + if (Lsb1) { + if (!(word0(&rv) & Lsb1)) + break; + } + else if (!(word1(&rv) & Lsb)) + break; +#else + if (!(word1(&rv) & LSB)) + break; +#endif +#endif + if (bc.dsign) +#ifdef Avoid_Underflow + dval(&rv) += sulp(&rv, &bc); +#else + dval(&rv) += ulp(&rv); +#endif +#ifndef ROUND_BIASED + else { +#ifdef Avoid_Underflow + dval(&rv) -= sulp(&rv, &bc); +#else + dval(&rv) -= ulp(&rv); +#endif +#ifndef Sudden_Underflow + if (!dval(&rv)) { + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } +#endif + } +#ifdef Avoid_Underflow + bc.dsign = 1 - bc.dsign; +#endif +#endif + break; + } + if ((aadj = ratio(delta, bs)) <= 2.) { + if (bc.dsign) + aadj = aadj1 = 1.; + else if (word1(&rv) || word0(&rv) & Bndry_mask) { +#ifndef Sudden_Underflow + if (word1(&rv) == Tiny1 && !word0(&rv)) { + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } +#endif + aadj = 1.; + aadj1 = -1.; + } + else { + /* special case -- power of FLT_RADIX to be */ + /* rounded down... */ + + if (aadj < 2./FLT_RADIX) + aadj = 1./FLT_RADIX; + else + aadj *= 0.5; + aadj1 = -aadj; + } + } + else { + aadj *= 0.5; + aadj1 = bc.dsign ? aadj : -aadj; +#ifdef Check_FLT_ROUNDS + switch(bc.rounding) { + case 2: /* towards +infinity */ + aadj1 -= 0.5; + break; + case 0: /* towards 0 */ + case 3: /* towards -infinity */ + aadj1 += 0.5; + } +#else + if (Flt_Rounds == 0) + aadj1 += 0.5; +#endif /*Check_FLT_ROUNDS*/ + } + y = word0(&rv) & Exp_mask; + + /* Check for overflow */ + + if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { + dval(&rv0) = dval(&rv); + word0(&rv) -= P*Exp_msk1; + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; + if ((word0(&rv) & Exp_mask) >= + Exp_msk1*(DBL_MAX_EXP+Bias-P)) { + if (word0(&rv0) == Big0 && word1(&rv0) == Big1) + goto ovfl; + word0(&rv) = Big0; + word1(&rv) = Big1; + goto cont; + } + else + word0(&rv) += P*Exp_msk1; + } + else { +#ifdef Avoid_Underflow + if (bc.scale && y <= 2*P*Exp_msk1) { + if (aadj <= 0x7fffffff) { + if ((z = aadj) <= 0) + z = 1; + aadj = z; + aadj1 = bc.dsign ? aadj : -aadj; + } + dval(&aadj2) = aadj1; + word0(&aadj2) += (2*P+1)*Exp_msk1 - y; + aadj1 = dval(&aadj2); + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; + if (rv.d == 0.) +#ifdef NO_STRTOD_BIGCOMP + goto undfl; +#else + { + if (bc.nd > nd) + bc.dsign = 1; + break; + } +#endif + } + else { + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; + } +#else +#ifdef Sudden_Underflow + if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { + dval(&rv0) = dval(&rv); + word0(&rv) += P*Exp_msk1; + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; +#ifdef IBM + if ((word0(&rv) & Exp_mask) < P*Exp_msk1) +#else + if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) +#endif + { + if (word0(&rv0) == Tiny0 + && word1(&rv0) == Tiny1) { + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } + word0(&rv) = Tiny0; + word1(&rv) = Tiny1; + goto cont; + } + else + word0(&rv) -= P*Exp_msk1; + } + else { + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; + } +#else /*Sudden_Underflow*/ + /* Compute adj so that the IEEE rounding rules will + * correctly round rv + adj in some half-way cases. + * If rv * ulp(rv) is denormalized (i.e., + * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid + * trouble from bits lost to denormalization; + * example: 1.2e-307 . + */ + if (y <= (P-1)*Exp_msk1 && aadj > 1.) { + aadj1 = (double)(int)(aadj + 0.5); + if (!bc.dsign) + aadj1 = -aadj1; + } + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + } + z = word0(&rv) & Exp_mask; +#ifndef SET_INEXACT + if (bc.nd == nd) { +#ifdef Avoid_Underflow + if (!bc.scale) +#endif + if (y == z) { + /* Can we stop now? */ + L = (Long)aadj; + aadj -= L; + /* The tolerances below are conservative. */ + if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask) { + if (aadj < .4999999 || aadj > .5000001) + break; + } + else if (aadj < .4999999/FLT_RADIX) + break; + } + } +#endif + cont: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(delta); + } + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); +#ifndef NO_STRTOD_BIGCOMP + if (req_bigcomp) { + bd0 = 0; + bc.e0 += nz1; + bigcomp(&rv, s0, &bc); + y = word0(&rv) & Exp_mask; + if (y == Exp_mask) + goto ovfl; + if (y == 0 && rv.d == 0.) + goto undfl; + } +#endif +#ifdef SET_INEXACT + if (bc.inexact) { + if (!oldinexact) { + word0(&rv0) = Exp_1 + (70 << Exp_shift); + word1(&rv0) = 0; + dval(&rv0) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif +#ifdef Avoid_Underflow + if (bc.scale) { + word0(&rv0) = Exp_1 - 2*P*Exp_msk1; + word1(&rv0) = 0; + dval(&rv) *= dval(&rv0); +#ifndef NO_ERRNO + /* try to avoid the bug of testing an 8087 register value */ +#ifdef IEEE_Arith + if (!(word0(&rv) & Exp_mask)) +#else + if (word0(&rv) == 0 && word1(&rv) == 0) +#endif + errno = ERANGE; +#endif + } +#endif /* Avoid_Underflow */ +#ifdef SET_INEXACT + if (bc.inexact && !(word0(&rv) & Exp_mask)) { + /* set underflow bit */ + dval(&rv0) = 1e-300; + dval(&rv0) *= dval(&rv0); + } +#endif + ret: + if (se) + *se = (char *)s; + return sign ? -dval(&rv) : dval(&rv); + } + +#ifndef MULTIPLE_THREADS + static char *dtoa_result; +#endif + + static char * +#ifdef KR_headers +rv_alloc(i) int i; +#else +rv_alloc(int i) +#endif +{ + int j, k, *r; + + j = sizeof(ULong); + for(k = 0; + sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i; + j <<= 1) + k++; + r = (int*)Balloc(k); + *r = k; + return +#ifndef MULTIPLE_THREADS + dtoa_result = +#endif + (char *)(r+1); + } + + static char * +#ifdef KR_headers +nrv_alloc(s, rve, n) char *s, **rve; int n; +#else +nrv_alloc(const char *s, char **rve, int n) +#endif +{ + char *rv, *t; + + t = rv = rv_alloc(n); + while((*t = *s++)) t++; + if (rve) + *rve = t; + return rv; + } + +/* freedtoa(s) must be used to free values s returned by dtoa + * when MULTIPLE_THREADS is #defined. It should be used in all cases, + * but for consistency with earlier versions of dtoa, it is optional + * when MULTIPLE_THREADS is not defined. + */ + + void +#ifdef KR_headers +freedtoa(s) char *s; +#else +freedtoa(char *s) +#endif +{ + Bigint *b = (Bigint *)((int *)s - 1); + b->maxwds = 1 << (b->k = *(int*)b); + Bfree(b); +#ifndef MULTIPLE_THREADS + if (s == dtoa_result) + dtoa_result = 0; +#endif + } + +/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. + * + * Inspired by "How to Print Floating-Point Numbers Accurately" by + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. + * + * Modifications: + * 1. Rather than iterating, we use a simple numeric overestimate + * to determine k = floor(log10(d)). We scale relevant + * quantities using O(log2(k)) rather than O(k) multiplications. + * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't + * try to generate digits strictly left to right. Instead, we + * compute with fewer bits and propagate the carry if necessary + * when rounding the final digit up. This is often faster. + * 3. Under the assumption that input will be rounded nearest, + * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. + * That is, we allow equality in stopping tests when the + * round-nearest rule will give the same floating-point value + * as would satisfaction of the stopping test with strict + * inequality. + * 4. We remove common factors of powers of 2 from relevant + * quantities. + * 5. When converting floating-point integers less than 1e16, + * we use floating-point arithmetic rather than resorting + * to multiple-precision integers. + * 6. When asked to produce fewer than 15 digits, we first try + * to get by with floating-point arithmetic; we resort to + * multiple-precision integer arithmetic only if we cannot + * guarantee that the floating-point calculation has given + * the correctly rounded result. For k requested digits and + * "uniformly" distributed input, the probability is + * something like 10^(k-15) that we must resort to the Long + * calculation. + */ + + char * +dtoa +#ifdef KR_headers + (dd, mode, ndigits, decpt, sign, rve) + double dd; int mode, ndigits, *decpt, *sign; char **rve; +#else + (double dd, int mode, int ndigits, int *decpt, int *sign, char **rve) +#endif +{ + /* Arguments ndigits, decpt, sign are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If not null, *rve is set to point + to the end of the return value. If d is +-Infinity or NaN, + then *decpt is set to 9999. + + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4,5 ==> similar to 2 and 3, respectively, but (in + round-nearest mode) with the tests of mode 0 to + possibly return a shorter string that rounds to d. + With IEEE arithmetic and compilation with + -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same + as modes 2 and 3 when FLT_ROUNDS != 1. + 6-9 ==> Debugging modes similar to mode - 4: don't try + fast floating-point estimate (if applicable). + + Values of mode other than 0-9 are treated as mode 0. + + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. + */ + + int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, + j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + spec_case, try_quick; + Long L; +#ifndef Sudden_Underflow + int denorm; + ULong x; +#endif + Bigint *b, *b1, *delta, *mlo, *mhi, *S; + U d2, eps, u; + double ds; + char *s, *s0; +#ifndef No_leftright +#ifdef IEEE_Arith + U eps1; +#endif +#endif +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif +#ifdef Honor_FLT_ROUNDS /*{*/ + int Rounding; +#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ + Rounding = Flt_Rounds; +#else /*}{*/ + Rounding = 1; + switch(fegetround()) { + case FE_TOWARDZERO: Rounding = 0; break; + case FE_UPWARD: Rounding = 2; break; + case FE_DOWNWARD: Rounding = 3; + } +#endif /*}}*/ +#endif /*}*/ + +#ifndef MULTIPLE_THREADS + if (dtoa_result) { + freedtoa(dtoa_result); + dtoa_result = 0; + } +#endif + + u.d = dd; + if (word0(&u) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(&u) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + +#if defined(IEEE_Arith) + defined(VAX) +#ifdef IEEE_Arith + if ((word0(&u) & Exp_mask) == Exp_mask) +#else + if (word0(&u) == 0x8000) +#endif + { + /* Infinity or NaN */ + *decpt = 9999; +#ifdef IEEE_Arith + if (!word1(&u) && !(word0(&u) & 0xfffff)) + return nrv_alloc("Infinity", rve, 8); +#endif + return nrv_alloc("NaN", rve, 3); + } +#endif +#ifdef IBM + dval(&u) += 0; /* normalize */ +#endif + if (!dval(&u)) { + *decpt = 1; + return nrv_alloc("0", rve, 1); + } + +#ifdef SET_INEXACT + try_quick = oldinexact = get_inexact(); + inexact = 1; +#endif +#ifdef Honor_FLT_ROUNDS + if (Rounding >= 2) { + if (*sign) + Rounding = Rounding == 2 ? 0 : 2; + else + if (Rounding != 2) + Rounding = 0; + } +#endif + + b = d2b(&u, &be, &bbits); +#ifdef Sudden_Underflow + i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); +#else + if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) { +#endif + dval(&d2) = dval(&u); + word0(&d2) &= Frac_mask1; + word0(&d2) |= Exp_11; +#ifdef IBM + if (j = 11 - hi0bits(word0(&d2) & Frac_mask)) + dval(&d2) /= 1 << j; +#endif + + /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 + * log10(x) = log(x) / log(10) + * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) + * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) + * + * This suggests computing an approximation k to log10(d) by + * + * k = (i - Bias)*0.301029995663981 + * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); + * + * We want k to be too large rather than too small. + * The error in the first-order Taylor series approximation + * is in our favor, so we just round up the constant enough + * to compensate for any error in the multiplication of + * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, + * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, + * adding 1e-13 to the constant term more than suffices. + * Hence we adjust the constant term to 0.1760912590558. + * (We could get a more accurate k by invoking log10, + * but this is probably not worthwhile.) + */ + + i -= Bias; +#ifdef IBM + i <<= 2; + i += j; +#endif +#ifndef Sudden_Underflow + denorm = 0; + } + else { + /* d is denormalized */ + + i = bbits + be + (Bias + (P-1) - 1); + x = i > 32 ? word0(&u) << (64 - i) | word1(&u) >> (i - 32) + : word1(&u) << (32 - i); + dval(&d2) = x; + word0(&d2) -= 31*Exp_msk1; /* adjust exponent */ + i -= (Bias + (P-1) - 1) + 1; + denorm = 1; + } +#endif + ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + k = (int)ds; + if (ds < 0. && ds != k) + k--; /* want k = floor(ds) */ + k_check = 1; + if (k >= 0 && k <= Ten_pmax) { + if (dval(&u) < tens[k]) + k--; + k_check = 0; + } + j = bbits - i - 1; + if (j >= 0) { + b2 = 0; + s2 = j; + } + else { + b2 = -j; + s2 = 0; + } + if (k >= 0) { + b5 = 0; + s5 = k; + s2 += k; + } + else { + b2 -= k; + b5 = -k; + s5 = 0; + } + if (mode < 0 || mode > 9) + mode = 0; + +#ifndef SET_INEXACT +#ifdef Check_FLT_ROUNDS + try_quick = Rounding == 1; +#else + try_quick = 1; +#endif +#endif /*SET_INEXACT*/ + + if (mode > 5) { + mode -= 4; + try_quick = 0; + } + leftright = 1; + ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */ + /* silence erroneous "gcc -Wall" warning. */ + switch(mode) { + case 0: + case 1: + i = 18; + ndigits = 0; + break; + case 2: + leftright = 0; + /* no break */ + case 4: + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + break; + case 3: + leftright = 0; + /* no break */ + case 5: + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } + s = s0 = rv_alloc(i); + +#ifdef Honor_FLT_ROUNDS + if (mode > 1 && Rounding != 1) + leftright = 0; +#endif + + if (ilim >= 0 && ilim <= Quick_max && try_quick) { + + /* Try to get by with floating-point arithmetic. */ + + i = 0; + dval(&d2) = dval(&u); + k0 = k; + ilim0 = ilim; + ieps = 2; /* conservative */ + if (k > 0) { + ds = tens[k&0xf]; + j = k >> 4; + if (j & Bletch) { + /* prevent overflows */ + j &= Bletch - 1; + dval(&u) /= bigtens[n_bigtens-1]; + ieps++; + } + for(; j; j >>= 1, i++) + if (j & 1) { + ieps++; + ds *= bigtens[i]; + } + dval(&u) /= ds; + } + else if ((j1 = -k)) { + dval(&u) *= tens[j1 & 0xf]; + for(j = j1 >> 4; j; j >>= 1, i++) + if (j & 1) { + ieps++; + dval(&u) *= bigtens[i]; + } + } + if (k_check && dval(&u) < 1. && ilim > 0) { + if (ilim1 <= 0) + goto fast_failed; + ilim = ilim1; + k--; + dval(&u) *= 10.; + ieps++; + } + dval(&eps) = ieps*dval(&u) + 7.; + word0(&eps) -= (P-1)*Exp_msk1; + if (ilim == 0) { + S = mhi = 0; + dval(&u) -= 5.; + if (dval(&u) > dval(&eps)) + goto one_digit; + if (dval(&u) < -dval(&eps)) + goto no_digits; + goto fast_failed; + } +#ifndef No_leftright + if (leftright) { + /* Use Steele & White method of only + * generating digits needed. + */ + dval(&eps) = 0.5/tens[ilim-1] - dval(&eps); +#ifdef IEEE_Arith + if (k0 < 0 && j1 >= 307) { + eps1.d = 1.01e256; /* 1.01 allows roundoff in the next few lines */ + word0(&eps1) -= Exp_msk1 * (Bias+P-1); + dval(&eps1) *= tens[j1 & 0xf]; + for(i = 0, j = (j1-256) >> 4; j; j >>= 1, i++) + if (j & 1) + dval(&eps1) *= bigtens[i]; + if (eps.d < eps1.d) + eps.d = eps1.d; + } +#endif + for(i = 0;;) { + L = dval(&u); + dval(&u) -= L; + *s++ = '0' + (int)L; + if (1. - dval(&u) < dval(&eps)) + goto bump_up; + if (dval(&u) < dval(&eps)) + goto ret1; + if (++i >= ilim) + break; + dval(&eps) *= 10.; + dval(&u) *= 10.; + } + } + else { +#endif + /* Generate ilim digits, then fix them up. */ + dval(&eps) *= tens[ilim-1]; + for(i = 1;; i++, dval(&u) *= 10.) { + L = (Long)(dval(&u)); + if (!(dval(&u) -= L)) + ilim = i; + *s++ = '0' + (int)L; + if (i == ilim) { + if (dval(&u) > 0.5 + dval(&eps)) + goto bump_up; + else if (dval(&u) < 0.5 - dval(&eps)) { + while(*--s == '0'); + s++; + goto ret1; + } + break; + } + } +#ifndef No_leftright + } +#endif + fast_failed: + s = s0; + dval(&u) = dval(&d2); + k = k0; + ilim = ilim0; + } + + /* Do we have a "small" integer? */ + + if (be >= 0 && k <= Int_max) { + /* Yes. */ + ds = tens[k]; + if (ndigits < 0 && ilim <= 0) { + S = mhi = 0; + if (ilim < 0 || dval(&u) <= 5*ds) + goto no_digits; + goto one_digit; + } + for(i = 1;; i++, dval(&u) *= 10.) { + L = (Long)(dval(&u) / ds); + dval(&u) -= L*ds; +#ifdef Check_FLT_ROUNDS + /* If FLT_ROUNDS == 2, L will usually be high by 1 */ + if (dval(&u) < 0) { + L--; + dval(&u) += ds; + } +#endif + *s++ = '0' + (int)L; + if (!dval(&u)) { +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (i == ilim) { +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(Rounding) { + case 0: goto ret1; + case 2: goto bump_up; + } +#endif + dval(&u) += dval(&u); +#ifdef ROUND_BIASED + if (dval(&u) >= ds) +#else + if (dval(&u) > ds || (dval(&u) == ds && L & 1)) +#endif + { + bump_up: + while(*--s == '9') + if (s == s0) { + k++; + *s = '0'; + break; + } + ++*s++; + } + break; + } + } + goto ret1; + } + + m2 = b2; + m5 = b5; + mhi = mlo = 0; + if (leftright) { + i = +#ifndef Sudden_Underflow + denorm ? be + (Bias + (P-1) - 1 + 1) : +#endif +#ifdef IBM + 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); +#else + 1 + P - bbits; +#endif + b2 += i; + s2 += i; + mhi = i2b(1); + } + if (m2 > 0 && s2 > 0) { + i = m2 < s2 ? m2 : s2; + b2 -= i; + m2 -= i; + s2 -= i; + } + if (b5 > 0) { + if (leftright) { + if (m5 > 0) { + mhi = pow5mult(mhi, m5); + b1 = mult(mhi, b); + Bfree(b); + b = b1; + } + if ((j = b5 - m5)) + b = pow5mult(b, j); + } + else + b = pow5mult(b, b5); + } + S = i2b(1); + if (s5 > 0) + S = pow5mult(S, s5); + + /* Check for special case that d is a normalized power of 2. */ + + spec_case = 0; + if ((mode < 2 || leftright) +#ifdef Honor_FLT_ROUNDS + && Rounding == 1 +#endif + ) { + if (!word1(&u) && !(word0(&u) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(&u) & (Exp_mask & ~Exp_msk1) +#endif + ) { + /* The special case */ + b2 += Log2P; + s2 += Log2P; + spec_case = 1; + } + } + + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + * + * Perhaps we should just compute leading 28 bits of S once + * and for all and pass them and a shift to quorem, so it + * can do shifts and ors to compute the numerator for q. + */ + i = dshift(S, s2); + b2 += i; + m2 += i; + s2 += i; + if (b2 > 0) + b = lshift(b, b2); + if (s2 > 0) + S = lshift(S, s2); + if (k_check) { + if (cmp(b,S) < 0) { + k--; + b = multadd(b, 10, 0); /* we botched the k estimate */ + if (leftright) + mhi = multadd(mhi, 10, 0); + ilim = ilim1; + } + } + if (ilim <= 0 && (mode == 3 || mode == 5)) { + if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { + /* no digits, fcvt style */ + no_digits: + k = -1 - ndigits; + goto ret; + } + one_digit: + *s++ = '1'; + k++; + goto ret; + } + if (leftright) { + if (m2 > 0) + mhi = lshift(mhi, m2); + + /* Compute mlo -- check for special case + * that d is a normalized power of 2. + */ + + mlo = mhi; + if (spec_case) { + mhi = Balloc(mhi->k); + Bcopy(mhi, mlo); + mhi = lshift(mhi, Log2P); + } + + for(i = 1;;i++) { + dig = quorem(b,S) + '0'; + /* Do we yet have the shortest decimal string + * that will round to d? + */ + j = cmp(b, mlo); + delta = diff(S, mhi); + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(delta); +#ifndef ROUND_BIASED + if (j1 == 0 && mode != 1 && !(word1(&u) & 1) +#ifdef Honor_FLT_ROUNDS + && Rounding >= 1 +#endif + ) { + if (dig == '9') + goto round_9_up; + if (j > 0) + dig++; +#ifdef SET_INEXACT + else if (!b->x[0] && b->wds <= 1) + inexact = 0; +#endif + *s++ = dig; + goto ret; + } +#endif + if (j < 0 || (j == 0 && mode != 1 +#ifndef ROUND_BIASED + && !(word1(&u) & 1) +#endif + )) { + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto accept_dig; + } +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(Rounding) { + case 0: goto accept_dig; + case 2: goto keep_dig; + } +#endif /*Honor_FLT_ROUNDS*/ + if (j1 > 0) { + b = lshift(b, 1); + j1 = cmp(b, S); +#ifdef ROUND_BIASED + if (j1 >= 0 /*)*/ +#else + if ((j1 > 0 || (j1 == 0 && dig & 1)) +#endif + && dig++ == '9') + goto round_9_up; + } + accept_dig: + *s++ = dig; + goto ret; + } + if (j1 > 0) { +#ifdef Honor_FLT_ROUNDS + if (!Rounding) + goto accept_dig; +#endif + if (dig == '9') { /* possible if i == 1 */ + round_9_up: + *s++ = '9'; + goto roundoff; + } + *s++ = dig + 1; + goto ret; + } +#ifdef Honor_FLT_ROUNDS + keep_dig: +#endif + *s++ = dig; + if (i == ilim) + break; + b = multadd(b, 10, 0); + if (mlo == mhi) + mlo = mhi = multadd(mhi, 10, 0); + else { + mlo = multadd(mlo, 10, 0); + mhi = multadd(mhi, 10, 0); + } + } + } + else + for(i = 1;; i++) { + *s++ = dig = quorem(b,S) + '0'; + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto ret; + } + if (i >= ilim) + break; + b = multadd(b, 10, 0); + } + + /* Round off last digit */ + +#ifdef Honor_FLT_ROUNDS + switch(Rounding) { + case 0: goto trimzeros; + case 2: goto roundoff; + } +#endif + b = lshift(b, 1); + j = cmp(b, S); +#ifdef ROUND_BIASED + if (j >= 0) +#else + if (j > 0 || (j == 0 && dig & 1)) +#endif + { + roundoff: + while(*--s == '9') + if (s == s0) { + k++; + *s++ = '1'; + goto ret; + } + ++*s++; + } + else { +#ifdef Honor_FLT_ROUNDS + trimzeros: +#endif + while(*--s == '0'); + s++; + } + ret: + Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + ret1: +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(&u) = Exp_1 + (70 << Exp_shift); + word1(&u) = 0; + dval(&u) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif + Bfree(b); + *s = 0; + *decpt = k + 1; + if (rve) + *rve = s; + return s0; + } +#ifdef __cplusplus +} +#endif From 66fd70236310bb91cdfaeef239fef57a639658f8 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sat, 1 Sep 2012 17:56:34 +0100 Subject: [PATCH 016/284] Minor changes to dtoa.c to make it easier to work with. - Change memory allocation to thread a context structure through the code rather than using globals (which would require a -lpthread and some locking to become threadsafe). - Remove a few configuration options (the "private memory" space, and K&R style headers). - Prefix exported symbols with jvp_ to prevent libc conflicts. - Add jvp_dtoa.h - Include netlib's g_fmt.c into dtoa.c - Add a few not-strictly-necessary initialisations in order to compile cleanly with gcc -Wall --- c/{dtoa.c => jv_dtoa.c} | 793 ++++++++++++++++++---------------------- c/jv_dtoa.h | 20 + 2 files changed, 373 insertions(+), 440 deletions(-) rename c/{dtoa.c => jv_dtoa.c} (89%) create mode 100644 c/jv_dtoa.h diff --git a/c/dtoa.c b/c/jv_dtoa.c similarity index 89% rename from c/dtoa.c rename to c/jv_dtoa.c index 41ed6982..1388943b 100644 --- a/c/dtoa.c +++ b/c/jv_dtoa.c @@ -1,3 +1,4 @@ + /**************************************************************** * * The author of this software is David M. Gay. @@ -186,6 +187,15 @@ * used for input more than STRTOD_DIGLIM digits long (default 40). */ +#define IEEE_8087 +#define NO_ERRNO +#define NO_HEX_FP +#define No_Hex_NaN +#define Long int + +#include "jv_dtoa.h" + + #ifndef Long #define Long long #endif @@ -212,23 +222,11 @@ typedef unsigned Long ULong; #endif #ifdef MALLOC -#ifdef KR_headers -extern char *MALLOC(); -#else extern void *MALLOC(size_t); -#endif #else #define MALLOC malloc #endif -#ifndef Omit_Private_Memory -#ifndef PRIVATE_MEM -#define PRIVATE_MEM 2304 -#endif -#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) -static double private_mem[PRIVATE_mem], *pmem_next = private_mem; -#endif - #undef IEEE_Arith #undef Avoid_Underflow #ifdef IEEE_MC68k @@ -292,12 +290,8 @@ extern "C" { #endif #ifndef CONST -#ifdef KR_headers -#define CONST /* blank */ -#else #define CONST const #endif -#endif #if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. @@ -470,11 +464,7 @@ extern int strtod_diglim; #ifdef RND_PRODQUOT #define rounded_product(a,b) a = rnd_prod(a, b) #define rounded_quotient(a,b) a = rnd_quot(a, b) -#ifdef KR_headers -extern double rnd_prod(), rnd_quot(); -#else extern double rnd_prod(double, double), rnd_quot(double, double); -#endif #else #define rounded_product(a,b) a *= b #define rounded_quotient(a,b) a /= b @@ -491,11 +481,7 @@ typedef struct BCinfo BCinfo; struct BCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflchk; }; -#ifdef KR_headers -#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff) -#else #define FFFFFFFF 0xffffffffUL -#endif #ifdef NO_LONG_LONG #undef ULLong @@ -516,18 +502,7 @@ BCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflc #endif #endif /* NO_LONG_LONG */ -#ifndef MULTIPLE_THREADS -#define ACQUIRE_DTOA_LOCK(n) /*nothing*/ -#define FREE_DTOA_LOCK(n) /*nothing*/ -#endif -#define Kmax 7 - -#ifdef __cplusplus -extern "C" double strtod(const char *s00, char **se); -extern "C" char *dtoa(double d, int mode, int ndigits, - int *decpt, int *sign, char **rve); -#endif struct Bigint { @@ -538,56 +513,38 @@ Bigint { typedef struct Bigint Bigint; - static Bigint *freelist[Kmax+1]; +void jvp_dtoa_context_init(struct dtoa_context* C) { + int i; + for (i=0; i<(int)(sizeof(C->freelist)/sizeof(C->freelist[0])); i++) { + C->freelist[i] = 0; + } + C->p5s = 0; +} + static Bigint * -Balloc -#ifdef KR_headers - (k) int k; -#else - (int k) -#endif + Balloc(struct dtoa_context* C, int k) { int x; Bigint *rv; -#ifndef Omit_Private_Memory - unsigned int len; -#endif - ACQUIRE_DTOA_LOCK(0); /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */ /* but this case seems very unlikely. */ - if (k <= Kmax && (rv = freelist[k])) - freelist[k] = rv->next; + if (k <= Kmax && (rv = C->freelist[k])) + C->freelist[k] = rv->next; else { x = 1 << k; -#ifdef Omit_Private_Memory rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); -#else - len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) - /sizeof(double); - if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) { - rv = (Bigint*)pmem_next; - pmem_next += len; - } - else - rv = (Bigint*)MALLOC(len*sizeof(double)); -#endif rv->k = k; rv->maxwds = x; } - FREE_DTOA_LOCK(0); rv->sign = rv->wds = 0; return rv; } static void Bfree -#ifdef KR_headers - (v) Bigint *v; -#else - (Bigint *v) -#endif + (struct dtoa_context* C, Bigint *v) { if (v) { if (v->k > Kmax) @@ -597,24 +554,36 @@ Bfree free((void*)v); #endif else { - ACQUIRE_DTOA_LOCK(0); - v->next = freelist[v->k]; - freelist[v->k] = v; - FREE_DTOA_LOCK(0); + v->next = C->freelist[v->k]; + C->freelist[v->k] = v; } } } + +void jvp_dtoa_context_free(struct dtoa_context* C) { + int k; + while (C->p5s) { + Bigint* p5 = C->p5s; + C->p5s = p5->next; + Bfree(C, p5); + } + for (k=0; k<(int)(sizeof(C->freelist)/sizeof(C->freelist[0])); k++) { + while (C->freelist[k]) { + Bigint* v = C->freelist[k]; + C->freelist[k] = v->next; + free(v); + } + } +} + + #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ y->wds*sizeof(Long) + 2*sizeof(int)) static Bigint * multadd -#ifdef KR_headers - (b, m, a) Bigint *b; int m, a; -#else - (Bigint *b, int m, int a) /* multiply by m and add a */ -#endif + (struct dtoa_context* C, Bigint *b, int m, int a) /* multiply by m and add a */ { int i, wds; #ifdef ULLong @@ -654,9 +623,9 @@ multadd while(++i < wds); if (carry) { if (wds >= b->maxwds) { - b1 = Balloc(b->k+1); + b1 = Balloc(C, b->k+1); Bcopy(b1, b); - Bfree(b); + Bfree(C, b); b = b1; } b->x[wds++] = carry; @@ -667,11 +636,7 @@ multadd static Bigint * s2b -#ifdef KR_headers - (s, nd0, nd, y9, dplen) CONST char *s; int nd0, nd, dplen; ULong y9; -#else - (const char *s, int nd0, int nd, ULong y9, int dplen) -#endif + (struct dtoa_context* C, const char *s, int nd0, int nd, ULong y9, int dplen) { Bigint *b; int i, k; @@ -680,11 +645,11 @@ s2b x = (nd + 8) / 9; for(k = 0, y = 1; x > y; y <<= 1, k++) ; #ifdef Pack_32 - b = Balloc(k); + b = Balloc(C, k); b->x[0] = y9; b->wds = 1; #else - b = Balloc(k+1); + b = Balloc(C, k+1); b->x[0] = y9 & 0xffff; b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; #endif @@ -692,24 +657,20 @@ s2b i = 9; if (9 < nd0) { s += 9; - do b = multadd(b, 10, *s++ - '0'); + do b = multadd(C, b, 10, *s++ - '0'); while(++i < nd0); s += dplen; } else s += dplen + 9; for(; i < nd; i++) - b = multadd(b, 10, *s++ - '0'); + b = multadd(C, b, 10, *s++ - '0'); return b; } static int hi0bits -#ifdef KR_headers - (x) ULong x; -#else - (ULong x) -#endif + (struct dtoa_context* C, ULong x) { int k = 0; @@ -739,11 +700,7 @@ hi0bits static int lo0bits -#ifdef KR_headers - (y) ULong *y; -#else - (ULong *y) -#endif + (struct dtoa_context* C, ULong *y) { int k; ULong x = *y; @@ -787,15 +744,11 @@ lo0bits static Bigint * i2b -#ifdef KR_headers - (i) int i; -#else - (int i) -#endif + (struct dtoa_context* C, int i) { Bigint *b; - b = Balloc(1); + b = Balloc(C, 1); b->x[0] = i; b->wds = 1; return b; @@ -803,11 +756,7 @@ i2b static Bigint * mult -#ifdef KR_headers - (a, b) Bigint *a, *b; -#else - (Bigint *a, Bigint *b) -#endif + (struct dtoa_context* C, Bigint *a, Bigint *b) { Bigint *c; int k, wa, wb, wc; @@ -833,7 +782,7 @@ mult wc = wa + wb; if (wc > a->maxwds) k++; - c = Balloc(k); + c = Balloc(C, k); for(x = c->x, xa = x + wc; x < xa; x++) *x = 0; xa = a->x; @@ -911,59 +860,36 @@ mult return c; } - static Bigint *p5s; static Bigint * pow5mult -#ifdef KR_headers - (b, k) Bigint *b; int k; -#else - (Bigint *b, int k) -#endif + (struct dtoa_context* C, Bigint *b, int k) { Bigint *b1, *p5, *p51; int i; static int p05[3] = { 5, 25, 125 }; if ((i = k & 3)) - b = multadd(b, p05[i-1], 0); + b = multadd(C, b, p05[i-1], 0); if (!(k >>= 2)) return b; - if (!(p5 = p5s)) { + if (!(p5 = C->p5s)) { /* first time */ -#ifdef MULTIPLE_THREADS - ACQUIRE_DTOA_LOCK(1); - if (!(p5 = p5s)) { - p5 = p5s = i2b(625); - p5->next = 0; - } - FREE_DTOA_LOCK(1); -#else - p5 = p5s = i2b(625); + p5 = C->p5s = i2b(C, 625); p5->next = 0; -#endif } for(;;) { if (k & 1) { - b1 = mult(b, p5); - Bfree(b); + b1 = mult(C, b, p5); + Bfree(C, b); b = b1; } if (!(k >>= 1)) break; if (!(p51 = p5->next)) { -#ifdef MULTIPLE_THREADS - ACQUIRE_DTOA_LOCK(1); - if (!(p51 = p5->next)) { - p51 = p5->next = mult(p5,p5); - p51->next = 0; - } - FREE_DTOA_LOCK(1); -#else - p51 = p5->next = mult(p5,p5); + p51 = p5->next = mult(C, p5,p5); p51->next = 0; -#endif } p5 = p51; } @@ -972,11 +898,7 @@ pow5mult static Bigint * lshift -#ifdef KR_headers - (b, k) Bigint *b; int k; -#else - (Bigint *b, int k) -#endif + (struct dtoa_context* C, Bigint *b, int k) { int i, k1, n, n1; Bigint *b1; @@ -991,7 +913,7 @@ lshift n1 = n + b->wds + 1; for(i = b->maxwds; n1 > i; i <<= 1) k1++; - b1 = Balloc(k1); + b1 = Balloc(C, k1); x1 = b1->x; for(i = 0; i < n; i++) *x1++ = 0; @@ -1026,17 +948,13 @@ lshift *x1++ = *x++; while(x < xe); b1->wds = n1 - 1; - Bfree(b); + Bfree(C, b); return b1; } static int cmp -#ifdef KR_headers - (a, b) Bigint *a, *b; -#else - (Bigint *a, Bigint *b) -#endif + (struct dtoa_context* C, Bigint *a, Bigint *b) { ULong *xa, *xa0, *xb, *xb0; int i, j; @@ -1066,11 +984,7 @@ cmp static Bigint * diff -#ifdef KR_headers - (a, b) Bigint *a, *b; -#else - (Bigint *a, Bigint *b) -#endif + (struct dtoa_context* C, Bigint *a, Bigint *b) { Bigint *c; int i, wa, wb; @@ -1084,9 +998,9 @@ diff #endif #endif - i = cmp(a,b); + i = cmp(C, a,b); if (!i) { - c = Balloc(0); + c = Balloc(C, 0); c->wds = 1; c->x[0] = 0; return c; @@ -1099,7 +1013,7 @@ diff } else i = 0; - c = Balloc(a->k); + c = Balloc(C, a->k); c->sign = i; wa = a->wds; xa = a->x; @@ -1160,11 +1074,7 @@ diff static double ulp -#ifdef KR_headers - (x) U *x; -#else - (U *x) -#endif + (struct dtoa_context* C, U *x) { Long L; U u; @@ -1202,11 +1112,7 @@ ulp static double b2d -#ifdef KR_headers - (a, e) Bigint *a; int *e; -#else - (Bigint *a, int *e) -#endif + (struct dtoa_context* C, Bigint *a, int *e) { ULong *xa, *xa0, w, y, z; int k; @@ -1224,7 +1130,7 @@ b2d #ifdef DEBUG if (!y) Bug("zero y in b2d"); #endif - k = hi0bits(y); + k = hi0bits(C, y); *e = 32 - k; #ifdef Pack_32 if (k < Ebits) { @@ -1272,11 +1178,7 @@ b2d static Bigint * d2b -#ifdef KR_headers - (d, e, bits) U *d; int *e, *bits; -#else - (U *d, int *e, int *bits) -#endif + (struct dtoa_context* C, U *d, int *e, int *bits) { Bigint *b; int de, k; @@ -1294,9 +1196,9 @@ d2b #endif #ifdef Pack_32 - b = Balloc(1); + b = Balloc(C, 1); #else - b = Balloc(2); + b = Balloc(C, 2); #endif x = b->x; @@ -1313,7 +1215,7 @@ d2b #endif #ifdef Pack_32 if ((y = d1)) { - if ((k = lo0bits(&y))) { + if ((k = lo0bits(C, &y))) { x[0] = y | z << (32 - k); z >>= k; } @@ -1325,7 +1227,7 @@ d2b b->wds = (x[1] = z) ? 2 : 1; } else { - k = lo0bits(&z); + k = lo0bits(C, &z); x[0] = z; #ifndef Sudden_Underflow i = @@ -1335,7 +1237,7 @@ d2b } #else if (y = d1) { - if (k = lo0bits(&y)) + if (k = lo0bits(C, &y)) if (k >= 16) { x[0] = y | z << 32 - k & 0xffff; x[1] = z >> k - 16 & 0xffff; @@ -1362,7 +1264,7 @@ d2b if (!z) Bug("Zero passed to d2b"); #endif - k = lo0bits(&z); + k = lo0bits(C, &z); if (k >= 16) { x[0] = z; i = 0; @@ -1383,7 +1285,7 @@ d2b #endif #ifdef IBM *e = (de - Bias - (P-1) << 2) + k; - *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); + *bits = 4*P + 8 - k - hi0bits(C, word0(d) & Frac_mask); #else *e = de - Bias - (P-1) + k; *bits = P - k; @@ -1393,9 +1295,9 @@ d2b else { *e = de - Bias - (P-1) + 1 + k; #ifdef Pack_32 - *bits = 32*i - hi0bits(x[i-1]); + *bits = 32*i - hi0bits(C, x[i-1]); #else - *bits = (i+2)*16 - hi0bits(x[i]); + *bits = (i+2)*16 - hi0bits(C, x[i]); #endif } #endif @@ -1406,17 +1308,13 @@ d2b static double ratio -#ifdef KR_headers - (a, b) Bigint *a, *b; -#else - (Bigint *a, Bigint *b) -#endif + (struct dtoa_context* C, Bigint *a, Bigint *b) { U da, db; int k, ka, kb; - dval(&da) = b2d(a, &ka); - dval(&db) = b2d(b, &kb); + dval(&da) = b2d(C, a, &ka); + dval(&db) = b2d(C, b, &kb); #ifdef Pack_32 k = ka - kb + 32*(a->wds - b->wds); #else @@ -1499,11 +1397,7 @@ static CONST double tinytens[] = { 1e-16, 1e-32 }; static unsigned char hexdig[256]; static void -#ifdef KR_headers -htinit(h, s, inc) unsigned char *h; unsigned char *s; int inc; -#else htinit(unsigned char *h, unsigned char *s, int inc) -#endif { int i, j; for(i = 0; (j = s[i]) !=0; i++) @@ -1511,11 +1405,7 @@ htinit(unsigned char *h, unsigned char *s, int inc) } static void -#ifdef KR_headers -hexdig_init() -#else hexdig_init(void) -#endif { #define USC (unsigned char *) htinit(hexdig, USC "0123456789", 0x10); @@ -1536,11 +1426,7 @@ hexdig_init(void) static int match -#ifdef KR_headers - (sp, t) char **sp, *t; -#else - (const char **sp, const char *t) -#endif + (struct dtoa_context* C, const char **sp, const char *t) { int c, d; CONST char *s = *sp; @@ -1558,11 +1444,7 @@ match #ifndef No_Hex_NaN static void hexnan -#ifdef KR_headers - (rvp, sp) U *rvp; CONST char **sp; -#else - (U *rvp, const char **sp) -#endif + (struct dtoa_context* C, U *rvp, const char **sp) { ULong c, x[2]; CONST char *s; @@ -1637,11 +1519,7 @@ hexnan #if !defined(NO_HEX_FP) || defined(Honor_FLT_ROUNDS) /*{*/ static Bigint * -#ifdef KR_headers -increment(b) Bigint *b; -#else -increment(Bigint *b) -#endif +increment(struct dtoa_context* C, Bigint *b) { ULong *x, *xe; Bigint *b1; @@ -1657,9 +1535,9 @@ increment(Bigint *b) } while(x < xe); { if (b->wds >= b->maxwds) { - b1 = Balloc(b->k+1); + b1 = Balloc(C, b->k+1); Bcopy(b1,b); - Bfree(b); + Bfree(C, b); b = b1; } b->x[b->wds++] = 1; @@ -1672,11 +1550,7 @@ increment(Bigint *b) #ifndef NO_HEX_FP /*{*/ static void -#ifdef KR_headers -rshift(b, k) Bigint *b; int k; -#else -rshift(Bigint *b, int k) -#endif +rshift(struct dtoa_context* C, Bigint *b, int k) { ULong *x, *x1, *xe, y; int n; @@ -1705,11 +1579,7 @@ rshift(Bigint *b, int k) } static ULong -#ifdef KR_headers -any_on(b, k) Bigint *b; int k; -#else any_on(Bigint *b, int k) -#endif { int n, nwds; ULong *x, *x0, x1, x2; @@ -1741,13 +1611,8 @@ enum { /* rounding values: same as FLT_ROUNDS */ Round_down = 3 }; - void -#ifdef KR_headers -gethex(sp, rvp, rounding, sign) - CONST char **sp; U *rvp; int rounding, sign; -#else -gethex( CONST char **sp, U *rvp, int rounding, int sign) -#endif +static void +gethex(struct dtoa_context* C, CONST char **sp, U *rvp, int rounding, int sign) { Bigint *b; CONST unsigned char *decpt, *s0, *s, *s1; @@ -1921,7 +1786,7 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign) n = s1 - s0 - 1; for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) k++; - b = Balloc(k); + b = Balloc(C, k); x = b->x; n = 0; L = 0; @@ -1948,7 +1813,7 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign) } *x++ = L; b->wds = n = x - b->x; - n = ULbits*n - hi0bits(L); + n = ULbits*n - hi0bits(C, L); nbits = Nbits; lostbits = 0; x = b->x; @@ -1963,18 +1828,18 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign) lostbits = 3; } } - rshift(b, n); + rshift(C, b, n); e += n; } else if (n < nbits) { n = nbits - n; - b = lshift(b, n); + b = lshift(C, b, n); e -= n; x = b->x; } if (e > Emax) { ovfl: - Bfree(b); + Bfree(C, b); ovfl1: #ifndef NO_ERRNO errno = ERANGE; @@ -2003,7 +1868,7 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign) goto ret_tiny; } #endif /* } IEEE_Arith */ - Bfree(b); + Bfree(C, b); retz: #ifndef NO_ERRNO errno = ERANGE; @@ -2020,7 +1885,7 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign) if (x[k>>kshift] & 1 << (k & kmask)) lostbits |= 2; nbits -= n; - rshift(b,n); + rshift(C, b,n); e = emin; } if (lostbits) { @@ -2041,7 +1906,7 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign) } if (up) { k = b->wds; - b = increment(b); + b = increment(C, b); x = b->x; if (denorm) { #if 0 @@ -2052,8 +1917,8 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign) } else if (b->wds > k || ((n = nbits & kmask) !=0 - && hi0bits(x[k-1]) < 32-n)) { - rshift(b,1); + && hi0bits(C, x[k-1]) < 32-n)) { + rshift(C, b,1); if (++e > Emax) goto ovfl; } @@ -2069,7 +1934,7 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign) #ifdef IBM if ((j = e & 3)) { k = b->x[0] & ((1 << j) - 1); - rshift(b,j); + rshift(C, b,j); if (k) { switch(rounding) { case Round_up: @@ -2098,18 +1963,14 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign) word0(rvp) = ((b->x[1] & ~0x800000) >> 16) | ((e + 129 + 55) << 7) | (b->x[1] << 16); word1(rvp) = (b->x[0] >> 16) | (b->x[0] << 16); #endif - Bfree(b); + Bfree(C, b); } #endif /*!NO_HEX_FP}*/ static int -#ifdef KR_headers -dshift(b, p2) Bigint *b; int p2; -#else -dshift(Bigint *b, int p2) -#endif +dshift(struct dtoa_context* C, Bigint *b, int p2) { - int rv = hi0bits(b->x[b->wds-1]) - 4; + int rv = hi0bits(C, b->x[b->wds-1]) - 4; if (p2 > 0) rv -= p2; return rv & kmask; @@ -2117,11 +1978,7 @@ dshift(Bigint *b, int p2) static int quorem -#ifdef KR_headers - (b, S) Bigint *b, *S; -#else - (Bigint *b, Bigint *S) -#endif + (struct dtoa_context* C, Bigint *b, Bigint *S) { int n; ULong *bx, *bxe, q, *sx, *sxe; @@ -2194,7 +2051,7 @@ quorem b->wds = n; } } - if (cmp(b, S) >= 0) { + if (cmp(C, b, S) >= 0) { q++; borrow = 0; carry = 0; @@ -2242,17 +2099,13 @@ quorem #if defined(Avoid_Underflow) || !defined(NO_STRTOD_BIGCOMP) /*{*/ static double sulp -#ifdef KR_headers - (x, bc) U *x; BCinfo *bc; -#else - (U *x, BCinfo *bc) -#endif + (struct dtoa_context* C, U *x, BCinfo *bc) { U u; double rv; int i; - rv = ulp(x); + rv = ulp(C, x); if (!bc->scale || (i = 2*P + 1 - ((word0(x) & Exp_mask) >> Exp_shift)) <= 0) return rv; /* Is there an example where i <= 0 ? */ word0(&u) = Exp_1 + (i << Exp_shift); @@ -2264,12 +2117,7 @@ sulp #ifndef NO_STRTOD_BIGCOMP static void bigcomp -#ifdef KR_headers - (rv, s0, bc) - U *rv; CONST char *s0; BCinfo *bc; -#else - (U *rv, const char *s0, BCinfo *bc) -#endif + (struct dtoa_context* C, U *rv, const char *s0, BCinfo *bc) { Bigint *b, *d; int b2, bbits, d2, dd, dig, dsign, i, j, nd, nd0, p2, p5, speccase; @@ -2282,7 +2130,7 @@ bigcomp #ifndef Sudden_Underflow if (rv->d == 0.) { /* special case: value near underflow-to-zero */ /* threshold was rounded to zero */ - b = i2b(1); + b = i2b(C, 1); p2 = Emin - P + 1; bbits = 1; #ifdef Avoid_Underflow @@ -2303,7 +2151,7 @@ bigcomp } else #endif - b = d2b(rv, &p2, &bbits); + b = d2b(C, rv, &p2, &bbits); #ifdef Avoid_Underflow p2 -= bc->scale; #endif @@ -2312,8 +2160,8 @@ bigcomp i = P - bbits; if (i > (j = P - Emin - 1 + p2)) { #ifdef Sudden_Underflow - Bfree(b); - b = i2b(1); + Bfree(C, b); + b = i2b(C, 1); p2 = Emin; i = P - 1; #ifdef Avoid_Underflow @@ -2329,28 +2177,28 @@ bigcomp #ifdef Honor_FLT_ROUNDS if (bc->rounding != 1) { if (i > 0) - b = lshift(b, i); + b = lshift(C, b, i); if (dsign) b = increment(b); } else #endif { - b = lshift(b, ++i); + b = lshift(C, b, ++i); b->x[0] |= 1; } #ifndef Sudden_Underflow have_i: #endif p2 -= p5 + i; - d = i2b(1); + d = i2b(C, 1); /* Arrange for convenient computation of quotients: * shift left if necessary so divisor has 4 leading 0 bits. */ if (p5 > 0) - d = pow5mult(d, p5); + d = pow5mult(C, d, p5); else if (p5 < 0) - b = pow5mult(b, -p5); + b = pow5mult(C, b, -p5); if (p2 > 0) { b2 = p2; d2 = 0; @@ -2359,18 +2207,18 @@ bigcomp b2 = 0; d2 = -p2; } - i = dshift(d, d2); + i = dshift(C, d, d2); if ((b2 += i) > 0) - b = lshift(b, b2); + b = lshift(C, b, b2); if ((d2 += i) > 0) - d = lshift(d, d2); + d = lshift(C, d, d2); /* Now b/d = exactly half-way between the two floating-point values */ /* on either side of the input string. Compute first digit of b/d. */ - if (!(dig = quorem(b,d))) { - b = multadd(b, 10, 0); /* very unlikely */ - dig = quorem(b,d); + if (!(dig = quorem(C, b,d))) { + b = multadd(C, b, 10, 0); /* very unlikely */ + dig = quorem(C, b,d); } /* Compare b/d with s0 */ @@ -2383,8 +2231,8 @@ bigcomp dd = 1; goto ret; } - b = multadd(b, 10, 0); - dig = quorem(b,d); + b = multadd(C, b, 10, 0); + dig = quorem(C, b,d); } for(j = bc->dp1; i++ < nd;) { if ((dd = s0[j++] - '0' - dig)) @@ -2394,14 +2242,14 @@ bigcomp dd = 1; goto ret; } - b = multadd(b, 10, 0); - dig = quorem(b,d); + b = multadd(C, b, 10, 0); + dig = quorem(C, b,d); } if (dig > 0 || b->x[0] || b->wds > 1) dd = -1; ret: - Bfree(b); - Bfree(d); + Bfree(C, b); + Bfree(C, d); #ifdef Honor_FLT_ROUNDS if (bc->rounding != 1) { if (dd < 0) { @@ -2420,7 +2268,7 @@ bigcomp } if (!dsign) goto rethi1; - dval(rv) += 2.*sulp(rv,bc); + dval(rv) += 2.*sulp(C, rv,bc); } else { bc->inexact = 0; @@ -2437,12 +2285,12 @@ bigcomp else if (dd < 0) { if (!dsign) /* does not happen for round-near */ retlow1: - dval(rv) -= sulp(rv,bc); + dval(rv) -= sulp(C, rv,bc); } else if (dd > 0) { if (dsign) { rethi1: - dval(rv) += sulp(rv,bc); + dval(rv) += sulp(C, rv,bc); } } else { @@ -2472,12 +2320,8 @@ retlow1: #endif /* NO_STRTOD_BIGCOMP */ double -strtod -#ifdef KR_headers - (s00, se) CONST char *s00; char **se; -#else - (const char *s00, char **se) -#endif +jvp_strtod + (struct dtoa_context* C, const char *s00, char **se) { int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1; int esign, i, j, k, nd, nd0, nf, nz, nz0, nz1, sign; @@ -2487,7 +2331,7 @@ strtod U aadj2, adj, rv, rv0; ULong y, z; BCinfo bc; - Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; + Bigint *bb=0, *bb1, *bd=0, *bd0, *bs=0, *delta=0; #ifdef Avoid_Underflow ULong Lsb, Lsb1; #endif @@ -2542,9 +2386,9 @@ strtod case 'x': case 'X': #ifdef Honor_FLT_ROUNDS - gethex(&s, &rv, bc.rounding, sign); + gethex(C, &s, &rv, bc.rounding, sign); #else - gethex(&s, &rv, 1, sign); + gethex(C, &s, &rv, 1, sign); #endif goto ret; } @@ -2665,9 +2509,9 @@ strtod switch(c) { case 'i': case 'I': - if (match(&s,"nf")) { + if (match(C, &s,"nf")) { --s; - if (!match(&s,"inity")) + if (!match(C, &s,"inity")) ++s; word0(&rv) = 0x7ff00000; word1(&rv) = 0; @@ -2676,12 +2520,12 @@ strtod break; case 'n': case 'N': - if (match(&s, "an")) { + if (match(C, &s, "an")) { word0(&rv) = NAN_WORD0; word1(&rv) = NAN_WORD1; #ifndef No_Hex_NaN if (*s == '(') /*)*/ - hexnan(&rv, &s); + hexnan(C, &rv, &s); #endif goto ret; } @@ -2842,11 +2686,11 @@ strtod #endif /*IEEE_Arith*/ range_err: if (bd0) { - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(bd0); - Bfree(delta); + Bfree(C, bb); + Bfree(C, bd); + Bfree(C, bs); + Bfree(C, bd0); + Bfree(C, delta); } #ifndef NO_ERRNO errno = ERANGE; @@ -2964,13 +2808,13 @@ strtod } } #endif - bd0 = s2b(s0, nd0, nd, y, bc.dplen); + bd0 = s2b(C, s0, nd0, nd, y, bc.dplen); for(;;) { - bd = Balloc(bd0->k); + bd = Balloc(C, bd0->k); Bcopy(bd, bd0); - bb = d2b(&rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ - bs = i2b(1); + bb = d2b(C, &rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ + bs = i2b(C, 1); if (e >= 0) { bb2 = bb5 = 0; @@ -3035,27 +2879,27 @@ strtod bs2 -= i; } if (bb5 > 0) { - bs = pow5mult(bs, bb5); - bb1 = mult(bs, bb); - Bfree(bb); + bs = pow5mult(C, bs, bb5); + bb1 = mult(C, bs, bb); + Bfree(C, bb); bb = bb1; } if (bb2 > 0) - bb = lshift(bb, bb2); + bb = lshift(C, bb, bb2); if (bd5 > 0) - bd = pow5mult(bd, bd5); + bd = pow5mult(C, bd, bd5); if (bd2 > 0) - bd = lshift(bd, bd2); + bd = lshift(C, bd, bd2); if (bs2 > 0) - bs = lshift(bs, bs2); - delta = diff(bb, bd); + bs = lshift(C, bs, bs2); + delta = diff(C, bb, bd); bc.dsign = delta->sign; delta->sign = 0; - i = cmp(delta, bs); + i = cmp(C, delta, bs); #ifndef NO_STRTOD_BIGCOMP /*{*/ if (bc.nd > nd && i <= 0) { if (bc.dsign) { - /* Must use bigcomp(). */ + /* Must use bigcomp(C, ). */ req_bigcomp = 1; break; } @@ -3099,8 +2943,8 @@ strtod if (y) #endif { - delta = lshift(delta,Log2P); - if (cmp(delta, bs) <= 0) + delta = lshift(C, delta,Log2P); + if (cmp(C, delta, bs) <= 0) adj.d = -0.5; } } @@ -3114,17 +2958,17 @@ strtod if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { word0(&rv) += P*Exp_msk1; - dval(&rv) += adj.d*ulp(dval(&rv)); + dval(&rv) += adj.d*ulp(C, dval(&rv)); word0(&rv) -= P*Exp_msk1; } else #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow}*/ - dval(&rv) += adj.d*ulp(&rv); + dval(&rv) += adj.d*ulp(C, &rv); } break; } - adj.d = ratio(delta, bs); + adj.d = ratio(C, delta, bs); if (adj.d < 1.) adj.d = 1.; if (adj.d <= 0x7ffffffe) { @@ -3143,7 +2987,7 @@ strtod #ifdef Sudden_Underflow if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { word0(&rv) += P*Exp_msk1; - adj.d *= ulp(dval(&rv)); + adj.d *= ulp(C, dval(&rv)); if (bc.dsign) dval(&rv) += adj.d; else @@ -3153,7 +2997,7 @@ strtod } #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow}*/ - adj.d *= ulp(&rv); + adj.d *= ulp(C, &rv); if (bc.dsign) { if (word0(&rv) == Big0 && word1(&rv) == Big1) goto ovfl; @@ -3191,8 +3035,8 @@ strtod #endif break; } - delta = lshift(delta,Log2P); - if (cmp(delta, bs) > 0) + delta = lshift(C, delta,Log2P); + if (cmp(C, delta, bs) > 0) goto drop_down; break; } @@ -3291,16 +3135,16 @@ strtod #endif if (bc.dsign) #ifdef Avoid_Underflow - dval(&rv) += sulp(&rv, &bc); + dval(&rv) += sulp(C, &rv, &bc); #else - dval(&rv) += ulp(&rv); + dval(&rv) += ulp(C, &rv); #endif #ifndef ROUND_BIASED else { #ifdef Avoid_Underflow - dval(&rv) -= sulp(&rv, &bc); + dval(&rv) -= sulp(C, &rv, &bc); #else - dval(&rv) -= ulp(&rv); + dval(&rv) -= ulp(C, &rv); #endif #ifndef Sudden_Underflow if (!dval(&rv)) { @@ -3318,7 +3162,7 @@ strtod #endif break; } - if ((aadj = ratio(delta, bs)) <= 2.) { + if ((aadj = ratio(C, delta, bs)) <= 2.) { if (bc.dsign) aadj = aadj1 = 1.; else if (word1(&rv) || word0(&rv) & Bndry_mask) { @@ -3369,7 +3213,7 @@ strtod if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { dval(&rv0) = dval(&rv); word0(&rv) -= P*Exp_msk1; - adj.d = aadj1 * ulp(&rv); + adj.d = aadj1 * ulp(C, &rv); dval(&rv) += adj.d; if ((word0(&rv) & Exp_mask) >= Exp_msk1*(DBL_MAX_EXP+Bias-P)) { @@ -3394,7 +3238,7 @@ strtod dval(&aadj2) = aadj1; word0(&aadj2) += (2*P+1)*Exp_msk1 - y; aadj1 = dval(&aadj2); - adj.d = aadj1 * ulp(&rv); + adj.d = aadj1 * ulp(C, &rv); dval(&rv) += adj.d; if (rv.d == 0.) #ifdef NO_STRTOD_BIGCOMP @@ -3408,7 +3252,7 @@ strtod #endif } else { - adj.d = aadj1 * ulp(&rv); + adj.d = aadj1 * ulp(C, &rv); dval(&rv) += adj.d; } #else @@ -3416,7 +3260,7 @@ strtod if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { dval(&rv0) = dval(&rv); word0(&rv) += P*Exp_msk1; - adj.d = aadj1 * ulp(&rv); + adj.d = aadj1 * ulp(C, &rv); dval(&rv) += adj.d; #ifdef IBM if ((word0(&rv) & Exp_mask) < P*Exp_msk1) @@ -3440,13 +3284,13 @@ strtod word0(&rv) -= P*Exp_msk1; } else { - adj.d = aadj1 * ulp(&rv); + adj.d = aadj1 * ulp(C, &rv); dval(&rv) += adj.d; } #else /*Sudden_Underflow*/ /* Compute adj so that the IEEE rounding rules will * correctly round rv + adj in some half-way cases. - * If rv * ulp(rv) is denormalized (i.e., + * If rv * ulp(C, rv) is denormalized (i.e., * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid * trouble from bits lost to denormalization; * example: 1.2e-307 . @@ -3456,7 +3300,7 @@ strtod if (!bc.dsign) aadj1 = -aadj1; } - adj.d = aadj1 * ulp(&rv); + adj.d = aadj1 * ulp(C, &rv); dval(&rv) += adj.d; #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ @@ -3482,21 +3326,21 @@ strtod } #endif cont: - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(delta); + Bfree(C, bb); + Bfree(C, bd); + Bfree(C, bs); + Bfree(C, delta); } - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(bd0); - Bfree(delta); + Bfree(C, bb); + Bfree(C, bd); + Bfree(C, bs); + Bfree(C, bd0); + Bfree(C, delta); #ifndef NO_STRTOD_BIGCOMP if (req_bigcomp) { bd0 = 0; bc.e0 += nz1; - bigcomp(&rv, s0, &bc); + bigcomp(C, &rv, s0, &bc); y = word0(&rv) & Exp_mask; if (y == Exp_mask) goto ovfl; @@ -3544,43 +3388,28 @@ strtod return sign ? -dval(&rv) : dval(&rv); } -#ifndef MULTIPLE_THREADS - static char *dtoa_result; -#endif - static char * -#ifdef KR_headers -rv_alloc(i) int i; -#else -rv_alloc(int i) -#endif +rv_alloc(struct dtoa_context* C, int i) { int j, k, *r; j = sizeof(ULong); for(k = 0; - sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i; + (int)(sizeof(Bigint) - sizeof(ULong) - sizeof(int)) + j <= i; j <<= 1) k++; - r = (int*)Balloc(k); + r = (int*)Balloc(C, k); *r = k; return -#ifndef MULTIPLE_THREADS - dtoa_result = -#endif (char *)(r+1); } static char * -#ifdef KR_headers -nrv_alloc(s, rve, n) char *s, **rve; int n; -#else -nrv_alloc(const char *s, char **rve, int n) -#endif +nrv_alloc(struct dtoa_context* C, const char *s, char **rve, int n) { char *rv, *t; - t = rv = rv_alloc(n); + t = rv = rv_alloc(C, n); while((*t = *s++)) t++; if (rve) *rve = t; @@ -3594,19 +3423,11 @@ nrv_alloc(const char *s, char **rve, int n) */ void -#ifdef KR_headers -freedtoa(s) char *s; -#else -freedtoa(char *s) -#endif +jvp_freedtoa(struct dtoa_context* C, char *s) { Bigint *b = (Bigint *)((int *)s - 1); b->maxwds = 1 << (b->k = *(int*)b); - Bfree(b); -#ifndef MULTIPLE_THREADS - if (s == dtoa_result) - dtoa_result = 0; -#endif + Bfree(C, b); } /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. @@ -3644,13 +3465,8 @@ freedtoa(char *s) */ char * -dtoa -#ifdef KR_headers - (dd, mode, ndigits, decpt, sign, rve) - double dd; int mode, ndigits, *decpt, *sign; char **rve; -#else - (double dd, int mode, int ndigits, int *decpt, int *sign, char **rve) -#endif +jvp_dtoa + (struct dtoa_context* C, double dd, int mode, int ndigits, int *decpt, int *sign, char **rve) { /* Arguments ndigits, decpt, sign are similar to those of ecvt and fcvt; trailing zeros are suppressed from @@ -3687,7 +3503,7 @@ dtoa */ int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, - j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + j, j1=0, k, k0, k_check, leftright, m2, m5, s2, s5, spec_case, try_quick; Long L; #ifndef Sudden_Underflow @@ -3720,12 +3536,6 @@ dtoa #endif /*}}*/ #endif /*}*/ -#ifndef MULTIPLE_THREADS - if (dtoa_result) { - freedtoa(dtoa_result); - dtoa_result = 0; - } -#endif u.d = dd; if (word0(&u) & Sign_bit) { @@ -3747,9 +3557,9 @@ dtoa *decpt = 9999; #ifdef IEEE_Arith if (!word1(&u) && !(word0(&u) & 0xfffff)) - return nrv_alloc("Infinity", rve, 8); + return nrv_alloc(C, "Infinity", rve, 8); #endif - return nrv_alloc("NaN", rve, 3); + return nrv_alloc(C, "NaN", rve, 3); } #endif #ifdef IBM @@ -3757,7 +3567,7 @@ dtoa #endif if (!dval(&u)) { *decpt = 1; - return nrv_alloc("0", rve, 1); + return nrv_alloc(C, "0", rve, 1); } #ifdef SET_INEXACT @@ -3774,7 +3584,7 @@ dtoa } #endif - b = d2b(&u, &be, &bbits); + b = d2b(C, &u, &be, &bbits); #ifdef Sudden_Underflow i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); #else @@ -3784,7 +3594,7 @@ dtoa word0(&d2) &= Frac_mask1; word0(&d2) |= Exp_11; #ifdef IBM - if (j = 11 - hi0bits(word0(&d2) & Frac_mask)) + if (j = 11 - hi0bits(C, word0(&d2) & Frac_mask)) dval(&d2) /= 1 << j; #endif @@ -3901,7 +3711,7 @@ dtoa if (i <= 0) i = 1; } - s = s0 = rv_alloc(i); + s = s0 = rv_alloc(C, i); #ifdef Honor_FLT_ROUNDS if (mode > 1 && Rounding != 1) @@ -4095,7 +3905,7 @@ dtoa #endif b2 += i; s2 += i; - mhi = i2b(1); + mhi = i2b(C, 1); } if (m2 > 0 && s2 > 0) { i = m2 < s2 ? m2 : s2; @@ -4106,20 +3916,20 @@ dtoa if (b5 > 0) { if (leftright) { if (m5 > 0) { - mhi = pow5mult(mhi, m5); - b1 = mult(mhi, b); - Bfree(b); + mhi = pow5mult(C, mhi, m5); + b1 = mult(C, mhi, b); + Bfree(C, b); b = b1; } if ((j = b5 - m5)) - b = pow5mult(b, j); + b = pow5mult(C, b, j); } else - b = pow5mult(b, b5); + b = pow5mult(C, b, b5); } - S = i2b(1); + S = i2b(C, 1); if (s5 > 0) - S = pow5mult(S, s5); + S = pow5mult(C, S, s5); /* Check for special case that d is a normalized power of 2. */ @@ -4148,25 +3958,25 @@ dtoa * and for all and pass them and a shift to quorem, so it * can do shifts and ors to compute the numerator for q. */ - i = dshift(S, s2); + i = dshift(C, S, s2); b2 += i; m2 += i; s2 += i; if (b2 > 0) - b = lshift(b, b2); + b = lshift(C, b, b2); if (s2 > 0) - S = lshift(S, s2); + S = lshift(C, S, s2); if (k_check) { - if (cmp(b,S) < 0) { + if (cmp(C, b,S) < 0) { k--; - b = multadd(b, 10, 0); /* we botched the k estimate */ + b = multadd(C, b, 10, 0); /* we botched the k estimate */ if (leftright) - mhi = multadd(mhi, 10, 0); + mhi = multadd(C, mhi, 10, 0); ilim = ilim1; } } if (ilim <= 0 && (mode == 3 || mode == 5)) { - if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { + if (ilim < 0 || cmp(C, b,S = multadd(C, S,5,0)) <= 0) { /* no digits, fcvt style */ no_digits: k = -1 - ndigits; @@ -4179,7 +3989,7 @@ dtoa } if (leftright) { if (m2 > 0) - mhi = lshift(mhi, m2); + mhi = lshift(C, mhi, m2); /* Compute mlo -- check for special case * that d is a normalized power of 2. @@ -4187,20 +3997,20 @@ dtoa mlo = mhi; if (spec_case) { - mhi = Balloc(mhi->k); + mhi = Balloc(C, mhi->k); Bcopy(mhi, mlo); - mhi = lshift(mhi, Log2P); + mhi = lshift(C, mhi, Log2P); } for(i = 1;;i++) { - dig = quorem(b,S) + '0'; + dig = quorem(C, b,S) + '0'; /* Do we yet have the shortest decimal string * that will round to d? */ - j = cmp(b, mlo); - delta = diff(S, mhi); - j1 = delta->sign ? 1 : cmp(b, delta); - Bfree(delta); + j = cmp(C, b, mlo); + delta = diff(C, S, mhi); + j1 = delta->sign ? 1 : cmp(C, b, delta); + Bfree(C, delta); #ifndef ROUND_BIASED if (j1 == 0 && mode != 1 && !(word1(&u) & 1) #ifdef Honor_FLT_ROUNDS @@ -4238,8 +4048,8 @@ dtoa } #endif /*Honor_FLT_ROUNDS*/ if (j1 > 0) { - b = lshift(b, 1); - j1 = cmp(b, S); + b = lshift(C, b, 1); + j1 = cmp(C, b, S); #ifdef ROUND_BIASED if (j1 >= 0 /*)*/ #else @@ -4271,18 +4081,18 @@ dtoa *s++ = dig; if (i == ilim) break; - b = multadd(b, 10, 0); + b = multadd(C, b, 10, 0); if (mlo == mhi) - mlo = mhi = multadd(mhi, 10, 0); + mlo = mhi = multadd(C, mhi, 10, 0); else { - mlo = multadd(mlo, 10, 0); - mhi = multadd(mhi, 10, 0); + mlo = multadd(C, mlo, 10, 0); + mhi = multadd(C, mhi, 10, 0); } } } else for(i = 1;; i++) { - *s++ = dig = quorem(b,S) + '0'; + *s++ = dig = quorem(C, b,S) + '0'; if (!b->x[0] && b->wds <= 1) { #ifdef SET_INEXACT inexact = 0; @@ -4291,7 +4101,7 @@ dtoa } if (i >= ilim) break; - b = multadd(b, 10, 0); + b = multadd(C, b, 10, 0); } /* Round off last digit */ @@ -4302,8 +4112,8 @@ dtoa case 2: goto roundoff; } #endif - b = lshift(b, 1); - j = cmp(b, S); + b = lshift(C, b, 1); + j = cmp(C, b, S); #ifdef ROUND_BIASED if (j >= 0) #else @@ -4327,11 +4137,11 @@ dtoa s++; } ret: - Bfree(S); + Bfree(C, S); if (mhi) { if (mlo && mlo != mhi) - Bfree(mlo); - Bfree(mhi); + Bfree(C, mlo); + Bfree(C, mhi); } ret1: #ifdef SET_INEXACT @@ -4345,7 +4155,7 @@ dtoa else if (!oldinexact) clear_inexact(); #endif - Bfree(b); + Bfree(C, b); *s = 0; *decpt = k + 1; if (rve) @@ -4355,3 +4165,106 @@ dtoa #ifdef __cplusplus } #endif + + + + + + + + +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 1996 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* g_fmt(buf,x) stores the closest decimal approximation to x in buf; + * it suffices to declare buf + * char buf[32]; + */ + + char * + jvp_dtoa_fmt(struct dtoa_context* C, register char *b, double x) +{ + register int i, k; + register char *s; + int decpt, j, sign; + char *b0, *s0, *se; + + b0 = b; +#ifdef IGNORE_ZERO_SIGN + if (!x) { + *b++ = '0'; + *b = 0; + goto done; + } +#endif + s = s0 = jvp_dtoa(C, x, 0, 0, &decpt, &sign, &se); + if (sign) + *b++ = '-'; + if (decpt == 9999) /* Infinity or Nan */ { + while((*b++ = *s++)); + goto done0; + } + if (decpt <= -4 || decpt > se - s + 5) { + *b++ = *s++; + if (*s) { + *b++ = '.'; + while((*b = *s++)) + b++; + } + *b++ = 'e'; + /* sprintf(b, "%+.2d", decpt - 1); */ + if (--decpt < 0) { + *b++ = '-'; + decpt = -decpt; + } + else + *b++ = '+'; + for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10); + for(;;) { + i = decpt / k; + *b++ = i + '0'; + if (--j <= 0) + break; + decpt -= i*k; + decpt *= 10; + } + *b = 0; + } + else if (decpt <= 0) { + *b++ = '.'; + for(; decpt < 0; decpt++) + *b++ = '0'; + while((*b++ = *s++)); + } + else { + while((*b = *s++)) { + b++; + if (--decpt == 0 && *s) + *b++ = '.'; + } + for(; decpt > 0; decpt--) + *b++ = '0'; + *b = 0; + } + done0: + jvp_freedtoa(C, s0); + goto done; + done: + return b0; + } diff --git a/c/jv_dtoa.h b/c/jv_dtoa.h new file mode 100644 index 00000000..e9346c0e --- /dev/null +++ b/c/jv_dtoa.h @@ -0,0 +1,20 @@ + +#define Kmax 7 + +struct Bigint; +struct dtoa_context { + struct Bigint *freelist[Kmax+1]; + struct Bigint *p5s; +}; + +void jvp_dtoa_context_init(struct dtoa_context* ctx); +void jvp_dtoa_context_free(struct dtoa_context* ctx); + +double jvp_strtod(struct dtoa_context* C, const char* s, char** se); + + +char* jvp_dtoa(struct dtoa_context* C, double dd, int mode, int ndigits, int *decpt, int *sign, char **rve); +void jvp_freedtoa(struct dtoa_context* C, char *s); + +#define JVP_DTOA_FMT_MAX_LEN 32 +char* jvp_dtoa_fmt(struct dtoa_context* C, register char *b, double x); From 92654f8204cebd88a350ea2a12c2cfb324003e1c Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sat, 1 Sep 2012 18:24:17 +0100 Subject: [PATCH 017/284] Fix a memory leak when inserting into an object with an already-present key --- c/jv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/c/jv.c b/c/jv.c index 09b600d8..6f72c9d4 100644 --- a/c/jv.c +++ b/c/jv.c @@ -602,6 +602,7 @@ static jv* jvp_object_write(jv_complex* object, jvp_string* key) { jvp_string_free_p(key); } else { slot = jvp_object_add_slot(object, key, bucket); + slot->value = jv_null(); } if (slot == 0) { jvp_object_rehash(object); @@ -609,6 +610,7 @@ static jv* jvp_object_write(jv_complex* object, jvp_string* key) { assert(!jvp_object_find_slot(object, key, bucket)); slot = jvp_object_add_slot(object, key, bucket); assert(slot); + slot->value = jv_null(); } return &slot->value; } @@ -654,7 +656,9 @@ jv jv_object_set(jv object, jv key, jv value) { assert(jv_get_kind(object) == JV_KIND_OBJECT); assert(jv_get_kind(key) == JV_KIND_STRING); // copy/free of object, key, value coalesced - *jvp_object_write(&object.val.complex, jvp_string_ptr(&key.val.complex)) = value; + jv* slot = jvp_object_write(&object.val.complex, jvp_string_ptr(&key.val.complex)); + jv_free(*slot); + *slot = value; return object; } From e98624e5a9aaee0cf359d11c1fc4769ec848ea4d Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sat, 1 Sep 2012 19:16:43 +0100 Subject: [PATCH 018/284] First pass at a JSON parser --- c/Makefile | 9 +- c/jv.h | 11 +- c/jv_parse.c | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++ c/jv_print.c | 59 ++++++++- c/jvtest.c | 2 - 5 files changed, 421 insertions(+), 11 deletions(-) create mode 100644 c/jv_parse.c diff --git a/c/Makefile b/c/Makefile index b77971da..08e72705 100644 --- a/c/Makefile +++ b/c/Makefile @@ -21,11 +21,12 @@ parsertest: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute $(CC) -o $@ $^ -ljansson jvtest: jvtest.c jv.c jv_print.c - $(CC) -o $@ $^ -ljansson + $(CC) -DNO_JANSSON -o $@ $^ + +jv_parse: jv_parse.c jv.c jv_print.c jv_dtoa.c + $(CC) -DNO_JANSSON -o $@ $^ + test: jvtest valgrind --error-exitcode=1 -q --leak-check=full ./jvtest -jsparse: jsparse.l jv.c - flex -o jsparse.c jsparse.l - gcc -o jsparse jsparse.c -ljansson \ No newline at end of file diff --git a/c/jv.h b/c/jv.h index 52158b72..d815827a 100644 --- a/c/jv.h +++ b/c/jv.h @@ -1,10 +1,11 @@ #ifndef JV_H #define JV_H -#include #include #include - +#include +#ifndef NO_JANSSON +#include static json_t* jv_lookup(json_t* t, json_t* k) { json_t* v; if (json_is_object(t) && json_is_string(k)) { @@ -38,7 +39,7 @@ static json_t* jv_insert(json_t* root, json_t* value, json_t** path, int pathlen } return jv_modify(root, *path, jv_insert(jv_lookup(root, *path), value, path+1, pathlen-1)); } - +#endif @@ -116,6 +117,10 @@ jv jv_object_iter_key(jv, int); jv jv_object_iter_value(jv, int); +void jv_dump(jv); + + + #endif diff --git a/c/jv_parse.c b/c/jv_parse.c new file mode 100644 index 00000000..4f7ef019 --- /dev/null +++ b/c/jv_parse.c @@ -0,0 +1,351 @@ +#include +#include +#include "jv.h" +#include "jv_dtoa.h" +jv stack[1000]; +int stackpos = 0; +jv next; +int hasnext; + +typedef const char* presult; + +#define TRY(x) do {presult msg__ = (x); if (msg__) return msg__; } while(0) +#ifdef __GNUC__ +#define pfunc __attribute__((warn_unused_result)) presult +#else +#define pfunc presult +#endif + + + +pfunc value(jv val) { + if (hasnext) return "Expected separator between values"; + hasnext = 1; + next = val; + return 0; +} + +void push(jv v) { + stack[stackpos++] = v; +} + +pfunc token(char ch) { + switch (ch) { + case '[': + if (hasnext) return "Expected separator between values"; + push(jv_array()); + break; + + case '{': + if (hasnext) return "Expected separator between values"; + push(jv_object()); + break; + + case ':': + if (!hasnext) + return "Expected string key before ':'"; + if (stackpos == 0 || jv_get_kind(stack[stackpos-1]) != JV_KIND_OBJECT) + return "':' not as part of an object"; + if (jv_get_kind(next) != JV_KIND_STRING) + return "Object keys must be strings"; + push(next); + hasnext = 0; + break; + + case ',': + if (!hasnext) + return "Expected value before ','"; + if (stackpos == 0) + return "',' not as part of an object or array"; + if (jv_get_kind(stack[stackpos-1]) == JV_KIND_ARRAY) { + stack[stackpos-1] = jv_array_append(stack[stackpos-1], next); + hasnext = 0; + } else if (jv_get_kind(stack[stackpos-1]) == JV_KIND_STRING) { + assert(stackpos > 1 && jv_get_kind(stack[stackpos-2]) == JV_KIND_OBJECT); + stack[stackpos-2] = jv_object_set(stack[stackpos-2], stack[stackpos-1], next); + stackpos--; + hasnext = 0; + } else { + // this case hits on input like {"a", "b"} + return "Objects must consist of key:value pairs"; + } + break; + + case ']': + if (stackpos == 0 || jv_get_kind(stack[stackpos-1]) != JV_KIND_ARRAY) + return "Unmatched ']'"; + if (hasnext) { + stack[stackpos-1] = jv_array_append(stack[stackpos-1], next); + hasnext = 0; + } else { + if (jv_array_length(jv_copy(stack[stackpos-1])) != 0) { + // this case hits on input like [1,2,3,] + return "Expected another array element"; + } + } + hasnext = 1; + next = stack[--stackpos]; + break; + + case '}': + if (stackpos == 0) + return "Unmatched '}'"; + if (hasnext) { + if (jv_get_kind(stack[stackpos-1]) != JV_KIND_STRING) + return "Objects must consist of key:value pairs"; + assert(stackpos > 1 && jv_get_kind(stack[stackpos-2]) == JV_KIND_OBJECT); + stack[stackpos-2] = jv_object_set(stack[stackpos-2], stack[stackpos-1], next); + stackpos--; + hasnext = 0; + } else { + if (jv_get_kind(stack[stackpos-1]) != JV_KIND_OBJECT) + return "Unmatched '}'"; + // FIXME: assert object empty + } + hasnext = 1; + next = stack[--stackpos]; + break; + } + return 0; +} + + +char tokenbuf[1000]; +int tokenpos; +struct dtoa_context dtoa; + +void tokenadd(char c) { + tokenbuf[tokenpos++] = c; +} + +int unhex4(char* hex) { + int r = 0; + for (int i=0; i<4; i++) { + char c = *hex++; + int n; + if ('0' <= c && c <= '9') n = c - '0'; + else if ('a' <= c && c <= 'f') n = c - 'a' + 10; + else if ('A' <= c && c <= 'F') n = c - 'A' + 10; + r <<= 4; + r |= n; + } + return r; +} + +int utf8_encode(int codepoint, char* out) { + assert(codepoint >= 0 && codepoint <= 0x10FFFF); + char* start = out; + if (codepoint <= 0x7F) { + *out++ = codepoint; + } else if (codepoint <= 0x7FF) { + *out++ = 0xC0 + ((codepoint & 0x7C0) >> 6); + *out++ = 0x80 + ((codepoint & 0x03F)); + } else if(codepoint <= 0xFFFF) { + *out++ = 0xE0 + ((codepoint & 0xF000) >> 12); + *out++ = 0x80 + ((codepoint & 0x0FC0) >> 6); + *out++ = 0x80 + ((codepoint & 0x003F)); + } else { + *out++ = 0xF0 + ((codepoint & 0x1C0000) >> 18); + *out++ = 0x80 + ((codepoint & 0x03F000) >> 12); + *out++ = 0x80 + ((codepoint & 0x000FC0) >> 6); + *out++ = 0x80 + ((codepoint & 0x00003F)); + } + return out - start; +} + +pfunc found_string() { + char* in = tokenbuf; + char* out = tokenbuf; + char* end = tokenbuf + tokenpos; + + while (in < end) { + char c = *in++; + if (c == '\\') { + if (in >= end) + return "Expected escape character at end of string"; + c = *in++; + switch (c) { + case '\\': + case '"': + case '/': *out++ = c; break; + case 'b': *out++ = '\b'; break; + case 'f': *out++ = '\f'; break; + case 't': *out++ = '\t'; break; + case 'n': *out++ = '\n'; break; + case 'r': *out++ = '\r'; break; + + case 'u': + /* ahh, the complicated case */ + if (in + 4 > end) + return "Invalid \\uXXXX escape"; + unsigned long codepoint = unhex4(in); + in += 4; + if (0xD800 <= codepoint && codepoint <= 0xDBFF) { + /* who thought UTF-16 surrogate pairs were a good idea? */ + if (in + 6 > end || in[0] != '\\' || in[1] != 'u') + return "Invalid \\uXXXX\\uXXXX surrogate pair escape"; + unsigned long surrogate = unhex4(in+2); + if (!(0xDC00 <= surrogate && surrogate <= 0xDFFF)) + return "Invalid \\uXXXX\\uXXXX surrogate pair escape"; + in += 6; + codepoint = 0x10000 + (((codepoint - 0xD800) << 10) + |(surrogate - 0xDC00)); + } + // FIXME assert valid codepoint + out += utf8_encode(codepoint, out); + break; + + default: + return "Invalid escape"; + } + } else { + *out++ = c; + } + } + TRY(value(jv_string_sized(tokenbuf, out - tokenbuf))); + tokenpos=0; + return 0; +} + +pfunc check_literal() { + if (tokenpos == 0) return 0; + + const char* pattern = 0; + int plen; + jv v; + switch (tokenbuf[0]) { + case 't': pattern = "true"; plen = 4; v = jv_true(); break; + case 'f': pattern = "false"; plen = 5; v = jv_false(); break; + case 'n': pattern = "null"; plen = 4; v = jv_null(); break; + } + if (pattern) { + if (tokenpos != plen) return "Invalid literal"; + for (int i=0; i -void jv_dump(jv x) { +#include "jv_dtoa.h" + +static void jv_dump_string(jv str, int ascii_only) { + assert(jv_get_kind(str) == JV_KIND_STRING); + const char* i = jv_string_value(str); + const char* end = i + jv_string_length(str); + while (i < end) { + int unicode_escape; + int c = (unsigned char)*i++; + if (0x20 <= c && c <= 0x7E) { + // printable ASCII + if (c == '"' || c == '\\') { + putchar('\\'); + } + putchar(c); + unicode_escape = 0; + } else if (c < 0x20 || c == 0x7F) { + // ASCII control character + switch (c) { + case '\b': + putchar('\\'); + putchar('b'); + break; + case '\t': + putchar('\\'); + putchar('t'); + break; + case '\r': + putchar('\\'); + putchar('r'); + break; + case '\n': + putchar('\\'); + putchar('n'); + break; + case '\f': + putchar('\\'); + putchar('f'); + break; + default: + unicode_escape = 1; + break; + } + } + } +} + +static void jv_dump_term(struct dtoa_context* C, jv x) { + char buf[JVP_DTOA_FMT_MAX_LEN]; switch (jv_get_kind(x)) { case JV_KIND_NULL: printf("null"); @@ -13,7 +61,7 @@ void jv_dump(jv x) { printf("true"); break; case JV_KIND_NUMBER: - printf("%f", jv_number_value(x)); + printf("%s", jvp_dtoa_fmt(C, buf, jv_number_value(x))); break; case JV_KIND_STRING: // FIXME: all sorts of broken @@ -43,3 +91,10 @@ void jv_dump(jv x) { } jv_free(x); } + +void jv_dump(jv x) { + struct dtoa_context C; + jvp_dtoa_context_init(&C); + jv_dump_term(&C, x); + jvp_dtoa_context_free(&C); +} diff --git a/c/jvtest.c b/c/jvtest.c index 667d706b..2b5a6276 100644 --- a/c/jvtest.c +++ b/c/jvtest.c @@ -3,8 +3,6 @@ #include #include "jv.h" -void jv_dump(jv); - int main(){ /// Arrays and numbers { From 22f8aed31e54dc801e9682c93cdbf51d8a83a303 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sun, 2 Sep 2012 00:24:23 +0100 Subject: [PATCH 019/284] Validation for empty objects Now (correctly) fails to parse {,} --- c/jv.c | 16 ++++++++++++++++ c/jv.h | 1 + c/jv_parse.c | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/c/jv.c b/c/jv.c index 6f72c9d4..3029904b 100644 --- a/c/jv.c +++ b/c/jv.c @@ -632,6 +632,15 @@ static int jvp_object_delete(jv_complex* object, jvp_string* key) { return 0; } +static int jvp_object_length(jv_complex* object) { + int n = 0; + for (int i=0; istring) n++; + } + return n; +} + /* * Objects (public interface) */ @@ -670,6 +679,13 @@ jv jv_object_delete(jv object, jv key) { return object; } +int jv_object_length(jv object) { + assert(jv_get_kind(object) == JV_KIND_OBJECT); + int n = jvp_object_length(&object.val.complex); + jv_free(object); + return n; +} + /* * Object iteration (internal helpers) */ diff --git a/c/jv.h b/c/jv.h index d815827a..44fe4798 100644 --- a/c/jv.h +++ b/c/jv.h @@ -109,6 +109,7 @@ jv jv_object(); jv jv_object_get(jv object, jv key); jv jv_object_set(jv object, jv key, jv value); jv jv_object_delete(jv object, jv key); +int jv_object_length(jv object); int jv_object_iter(jv); int jv_object_iter_next(jv, int); diff --git a/c/jv_parse.c b/c/jv_parse.c index 4f7ef019..31e8d68d 100644 --- a/c/jv_parse.c +++ b/c/jv_parse.c @@ -100,7 +100,8 @@ pfunc token(char ch) { } else { if (jv_get_kind(stack[stackpos-1]) != JV_KIND_OBJECT) return "Unmatched '}'"; - // FIXME: assert object empty + if (jv_object_length(jv_copy(stack[stackpos-1])) != 0) + return "Expected another key-value pair"; } hasnext = 1; next = stack[--stackpos]; From 2cb9a6e61dd9605cfd24d44695be5f0a1a00aaba Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sun, 2 Sep 2012 16:31:59 +0100 Subject: [PATCH 020/284] Move from Jansson to JV - everything but the interpreter loop Passes valgrind --leak-check=full. --- c/Makefile | 2 +- c/builtin.c | 30 ++++++++--------- c/bytecode.c | 22 +++++++++++-- c/bytecode.h | 9 ++++-- c/compile.c | 16 +++++---- c/compile.h | 2 +- c/jv.c | 6 ++-- c/jv.h | 91 ++++++++++++++++++++++++++++++---------------------- c/jv_parse.c | 24 ++++++++------ c/lexer.l | 4 +-- c/main.c | 36 ++++++++++++--------- c/parser.y | 51 +++++++++++++++-------------- 12 files changed, 170 insertions(+), 123 deletions(-) diff --git a/c/Makefile b/c/Makefile index 08e72705..bf33acf3 100644 --- a/c/Makefile +++ b/c/Makefile @@ -24,7 +24,7 @@ jvtest: jvtest.c jv.c jv_print.c $(CC) -DNO_JANSSON -o $@ $^ jv_parse: jv_parse.c jv.c jv_print.c jv_dtoa.c - $(CC) -DNO_JANSSON -o $@ $^ + $(CC) -DNO_JANSSON -o $@ $^ -DJV_PARSE_MAIN test: jvtest diff --git a/c/builtin.c b/c/builtin.c index ef37c28c..0252566a 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -1,28 +1,24 @@ #include "builtin.h" -#include - - -static void f_false(json_t* input[], json_t* output[]) { - output[0] = json_false(); +static void f_false(jv input[], jv output[]) { + output[0] = jv_false(); } -static void f_true(json_t* input[], json_t* output[]) { - output[0] = json_true(); +static void f_true(jv input[], jv output[]) { + output[0] = jv_true(); } -static void f_plus(json_t* input[], json_t* output[]) { - json_t* a = input[2]; - json_t* b = input[1]; - if (json_is_number(a) && json_is_number(b)) { - output[0] = json_real(json_number_value(a) + - json_number_value(b)); - } else if (json_is_array(a) && json_is_array(b)) { - output[0] = json_copy(a); - json_array_extend(output[0], b); +static void f_plus(jv input[], jv output[]) { + jv a = input[2]; + jv b = input[1]; + if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { + output[0] = jv_number(jv_number_value(a) + + jv_number_value(b)); + } else if (jv_get_kind(a) == JV_KIND_ARRAY && jv_get_kind(b) == JV_KIND_ARRAY) { + output[0] = jv_array_concat(a, b); } else { - output[0] = json_string("wtf gaize"); + output[0] = jv_string("wtf gaize"); } } diff --git a/c/bytecode.c b/c/bytecode.c index ef585bd7..208e82f0 100644 --- a/c/bytecode.c +++ b/c/bytecode.c @@ -1,6 +1,7 @@ #include #include -#include +#include + #include "bytecode.h" #include "opcode.h" @@ -57,8 +58,7 @@ void dump_operation(struct bytecode* bc, uint16_t* codeptr) { printf(" %04d", pc + imm); } else if (op->flags & OP_HAS_CONSTANT) { printf(" "); - json_dumpf(json_array_get(bc->constants, imm), - stdout, JSON_ENCODE_ANY); + jv_dump(jv_array_get(jv_copy(bc->constants), imm)); } else if (op->flags & OP_HAS_VARIABLE) { uint16_t v = bc->code[pc++]; printf(" v%d", v); @@ -70,3 +70,19 @@ void dump_operation(struct bytecode* bc, uint16_t* codeptr) { } } } + +void symbol_table_free(struct symbol_table* syms) { + free(syms->cfunctions); + free(syms); +} + +void bytecode_free(struct bytecode* bc) { + free(bc->code); + jv_free(bc->constants); + for (int i=0; insubfunctions; i++) + bytecode_free(bc->subfunctions[i]); + if (!bc->parent) + symbol_table_free(bc->globals); + free(bc->subfunctions); + free(bc); +} diff --git a/c/bytecode.h b/c/bytecode.h index b1146ad7..5ffe80a6 100644 --- a/c/bytecode.h +++ b/c/bytecode.h @@ -1,11 +1,11 @@ #ifndef BYTECODE_H #define BYTECODE_H -#include #include +#include "jv.h" #include "opcode.h" -typedef void (*cfunction_ptr)(json_t* input[], json_t* output[]); +typedef void (*cfunction_ptr)(jv input[], jv output[]); struct cfunction { cfunction_ptr fptr; @@ -33,7 +33,7 @@ struct bytecode { int nlocals; int nclosures; - json_t* constants; + jv constants; // JSON array of constants struct symbol_table* globals; struct bytecode** subfunctions; @@ -46,4 +46,7 @@ void dump_disassembly(int, struct bytecode* code); void dump_code(int, struct bytecode* code); void dump_operation(struct bytecode* bc, uint16_t* op); +void symbol_table_free(struct symbol_table* syms); +void bytecode_free(struct bytecode* bc); + #endif diff --git a/c/compile.c b/c/compile.c index dc90aed3..b7fcc4f2 100644 --- a/c/compile.c +++ b/c/compile.c @@ -1,5 +1,6 @@ #include #include +#include #include "opcode.h" #include "compile.h" @@ -13,7 +14,7 @@ struct inst { union { uint16_t intval; struct inst* target; - json_t* constant; + jv constant; struct cfunction* cfunc; } imm; @@ -52,6 +53,9 @@ static void inst_free(struct inst* i) { if (opcode_describe(i->op)->flags & OP_HAS_BLOCK) { block_free(i->subfn); } + if (opcode_describe(i->op)->flags & OP_HAS_CONSTANT) { + jv_free(i->imm.constant); + } free(i); } @@ -89,7 +93,7 @@ block gen_op_simple(opcode op) { } -block gen_op_const(opcode op, json_t* constant) { +block gen_op_const(opcode op, jv constant) { assert(opcode_describe(op)->flags & OP_HAS_CONSTANT); inst* i = inst_new(op); i->imm.constant = constant; @@ -267,7 +271,7 @@ block gen_both(block a, block b) { block gen_collect(block expr) { block c = gen_noop(); block_append(&c, gen_op_simple(DUP)); - block_append(&c, gen_op_const(LOADK, json_array())); + block_append(&c, gen_op_const(LOADK, jv_array())); block array_var = block_bind(gen_op_var_unbound(STOREV, "collect"), gen_noop(), OP_HAS_VARIABLE); block_append(&c, array_var); @@ -395,7 +399,7 @@ static void compile(struct bytecode* bc, block b) { uint16_t* code = malloc(sizeof(uint16_t) * bc->codelen); bc->code = code; pos = 0; - json_t* constant_pool = json_array(); + jv constant_pool = jv_array(); int maxvar = -1; for (inst* curr = b.first; curr; curr = curr->next) { const struct opcode_description* op = opcode_describe(curr->op); @@ -436,8 +440,8 @@ static void compile(struct bytecode* bc, block b) { } assert(nargs - 1 == desired_params); } else if (opflags & OP_HAS_CONSTANT) { - code[pos++] = json_array_size(constant_pool); - json_array_append(constant_pool, curr->imm.constant); + code[pos++] = jv_array_length(jv_copy(constant_pool)); + constant_pool = jv_array_append(constant_pool, jv_copy(curr->imm.constant)); } else if (opflags & OP_HAS_VARIABLE) { code[pos++] = nesting_level(bc, curr->bound_by); uint16_t var = (uint16_t)curr->bound_by->imm.intval; diff --git a/c/compile.h b/c/compile.h index 4c0a3a17..5f0be89b 100644 --- a/c/compile.h +++ b/c/compile.h @@ -13,7 +13,7 @@ typedef struct block { block gen_noop(); block gen_op_simple(opcode op); -block gen_op_const(opcode op, json_t* constant); +block gen_op_const(opcode op, jv constant); block gen_op_target(opcode op, block target); block gen_op_var_unbound(opcode op, const char* name); block gen_op_var_bound(opcode op, block binder); diff --git a/c/jv.c b/c/jv.c index 3029904b..7944d642 100644 --- a/c/jv.c +++ b/c/jv.c @@ -278,7 +278,7 @@ static jvp_string* jvp_string_alloc(uint32_t size) { return s; } -static jv_complex jvp_string_new(char* data, uint32_t length) { +static jv_complex jvp_string_new(const char* data, uint32_t length) { jvp_string* s = jvp_string_alloc(length); memcpy(s->data, data, length); s->data[length] = 0; @@ -389,14 +389,14 @@ static int jvp_string_equal(jv_complex* a, jv_complex* b) { * Strings (public API) */ -jv jv_string_sized(char* str, int len) { +jv jv_string_sized(const char* str, int len) { jv j; j.kind = JV_KIND_STRING; j.val.complex = jvp_string_new(str, len); return j; } -jv jv_string(char* str) { +jv jv_string(const char* str) { return jv_string_sized(str, strlen(str)); } diff --git a/c/jv.h b/c/jv.h index 44fe4798..7696b03b 100644 --- a/c/jv.h +++ b/c/jv.h @@ -4,42 +4,6 @@ #include #include #include -#ifndef NO_JANSSON -#include -static json_t* jv_lookup(json_t* t, json_t* k) { - json_t* v; - if (json_is_object(t) && json_is_string(k)) { - v = json_object_get(t, json_string_value(k)); - } else if (json_is_array(t) && json_is_number(k)) { - v = json_array_get(t, json_integer_value(k)); - } else { - assert(0&&"bad lookup"); - } - if (v) - return v; - else - return json_null(); -} - -static json_t* jv_modify(json_t* t, json_t* k, json_t* v) { - t = json_copy(t); - if (json_is_object(t) && json_is_string(k)) { - json_object_set(t, json_string_value(k), v); - } else if (json_is_array(t) && json_is_number(k)) { - json_array_set(t, json_integer_value(k), v); - } else { - assert(0 && "bad mod"); - } - return t; -} - -static json_t* jv_insert(json_t* root, json_t* value, json_t** path, int pathlen) { - if (pathlen == 0) { - return value; - } - return jv_modify(root, *path, jv_insert(jv_lookup(root, *path), value, path+1, pathlen-1)); -} -#endif @@ -99,8 +63,8 @@ jv jv_array_concat(jv, jv); jv jv_array_slice(jv, int, int); -jv jv_string(char*); -jv jv_string_sized(char*, int); +jv jv_string(const char*); +jv jv_string_sized(const char*, int); int jv_string_length(jv); uint32_t jv_string_hash(jv); const char* jv_string_value(jv); @@ -119,6 +83,57 @@ jv jv_object_iter_value(jv, int); void jv_dump(jv); +jv jv_parse(const char* string); + + + + + +static jv jv_lookup(jv t, jv k) { + jv v; + if (jv_get_kind(t) == JV_KIND_OBJECT && jv_get_kind(k) == JV_KIND_STRING) { + v = jv_object_get(t, k); + } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_NUMBER) { + // FIXME: don't do lookup for noninteger index + v = jv_array_get(t, (int)jv_number_value(k)); + } else { + assert(0&&"bad lookup"); + } + return v; + // FIXME: invalid indexes, JV_KIND_INVALID + /* + if (v) + return v; + else + return jv_null(); + */ +} + +static jv jv_modify(jv t, jv k, jv v) { + if (jv_get_kind(t) == JV_KIND_OBJECT && jv_get_kind(k) == JV_KIND_STRING) { + t = jv_object_set(t, k, v); + } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_NUMBER) { + t = jv_array_set(t, (int)jv_number_value(k), v); + } else { + assert(0 && "bad mod"); + } + return t; +} + +static jv jv_insert(jv root, jv value, jv* path, int pathlen) { + if (pathlen == 0) { + jv_free(root); + return value; + } + return jv_modify(root, *path, + jv_insert(jv_lookup(jv_copy(root), jv_copy(*path)), value, path+1, pathlen-1)); +} + + + + + + diff --git a/c/jv_parse.c b/c/jv_parse.c index 31e8d68d..26c2cc38 100644 --- a/c/jv_parse.c +++ b/c/jv_parse.c @@ -327,26 +327,32 @@ pfunc finish() { return 0; } - -int main(int argc, char* argv[]) { - assert(argc == 2); +jv jv_parse(const char* string) { jvp_dtoa_context_init(&dtoa); - char* p = argv[1]; + + const char* p = string; char ch; while ((ch = *p++)) { presult msg = scan(ch); if (msg){ - printf("ERROR: %s\n", msg); - return 1; + printf("ERROR: %s (parsing [%s])\n", msg, string); + return jv_null(); } } presult msg = finish(); if (msg) { - printf("ERROR: %s\n", msg); - return 1; + printf("ERROR: %s (parsing [%s])\n", msg, string); + return jv_null(); } jvp_dtoa_context_free(&dtoa); - jv_dump(next); + hasnext = 0; + return next; +} +#if JV_PARSE_MAIN +int main(int argc, char* argv[]) { + assert(argc == 2); + jv_dump(jv_parse(argv[1])); printf("\n"); return 0; } +#endif diff --git a/c/lexer.l b/c/lexer.l index e4ffafce..34253b01 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -15,8 +15,8 @@ "|=" { return SETPIPE; } "."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];} -[[:digit:]]+ { yylval->num = atoi(yytext); return NUMBER;} -[[:alnum:]]+ { yylval->str = strdup(yytext); return IDENT;} +[[:digit:]]+ { yylval->literal = jv_number((double)atoi(yytext)); return LITERAL;} +[[:alnum:]]+ { yylval->literal = jv_string(yytext); return IDENT;} [ \n\t]+ {} %% /* perhaps these should be calls... */ diff --git a/c/main.c b/c/main.c index c03b5a99..56d8d1d2 100644 --- a/c/main.c +++ b/c/main.c @@ -2,13 +2,14 @@ #include "compile.h" #include "parser.tab.h" #include "builtin.h" +#include "jv.h" block compile(const char* str); -void jq_init(struct bytecode* bc, json_t* value); -json_t* jq_next(); +//void jq_init(struct bytecode* bc, jv value); +//jv jq_next(); -void run_program(struct bytecode* bc); +//void run_program(struct bytecode* bc); int skipline(const char* buf) { int p = 0; @@ -30,41 +31,44 @@ void run_tests() { block program = compile(buf); block_append(&program, gen_op_simple(YIELD)); block_append(&program, gen_op_simple(BACKTRACK)); - struct bytecode* bc = block_compile(gen_cbinding(&builtins, program)); + program = gen_cbinding(&builtins, program); + struct bytecode* bc = block_compile(program); block_free(program); printf("Disassembly:\n"); dump_disassembly(2, bc); printf("\n"); fgets(buf, sizeof(buf), testdata); - json_t* input = json_loads(buf, JSON_DECODE_ANY, 0); - jq_init(bc, input); + jv input = jv_parse(buf); + jv_free(input); //jq_init(bc, input); while (fgets(buf, sizeof(buf), testdata)) { if (skipline(buf)) break; - json_t* expected = json_loads(buf, JSON_DECODE_ANY, 0); - json_t* actual = jq_next(); - if (!actual) { + jv expected = jv_parse(buf); + //jv actual = jq_next(); FIXME + jv actual = jv_copy(expected); + if (!1) { printf("Insufficient results\n"); pass = 0; break; - } else if (!json_equal(expected, actual)) { + } else if (!jv_equal(expected, actual)) { printf("Expected "); - json_dumpf(expected, stdout, JSON_ENCODE_ANY); + jv_dump(expected); printf(", but got "); - json_dumpf(actual, stdout, JSON_ENCODE_ANY); + jv_dump(actual); printf("\n"); pass = 0; } } - if (pass) { - json_t* extra = jq_next(); + if (pass && 0) { /* + jv extra = jq_next(); if (extra) { printf("Superfluous result: "); json_dumpf(extra, stdout, JSON_ENCODE_ANY); printf("\n"); pass = 0; - } + }*/ } + bytecode_free(bc); tests++; passed+=pass; } @@ -80,5 +84,5 @@ int main(int argc, char* argv[]) { block_free(blk); dump_disassembly(0, bc); printf("\n"); - run_program(bc); + //run_program(bc); } diff --git a/c/parser.y b/c/parser.y index 5ec03892..14a338a7 100644 --- a/c/parser.y +++ b/c/parser.y @@ -7,8 +7,7 @@ %locations %define api.pure %union { - int num; - char* str; + jv literal; block blk; } @@ -17,8 +16,8 @@ %lex-param {yyscan_t lexer} -%token IDENT -%token NUMBER +%token IDENT +%token LITERAL /* revolting hack */ %left ';' @@ -48,10 +47,6 @@ static block gen_dictpair(block k, block v) { return b; } -static block gen_string(const char* str) { - return gen_op_const(LOADK, json_string(str)); -} - static block gen_index(block obj, block key) { return block_join(obj, block_join(gen_subexp(key), gen_op_simple(INDEX))); } @@ -64,18 +59,23 @@ program: Exp { *answer = $1; } Exp: "def" IDENT ':' Exp ';' Exp { block body = block_join($4, gen_op_simple(RET)); - $$ = block_bind(gen_op_block_defn(CLOSURE_CREATE, $2, body), $6, OP_IS_CALL_PSEUDO); + $$ = block_bind(gen_op_block_defn(CLOSURE_CREATE, jv_string_value($2), body), + $6, OP_IS_CALL_PSEUDO); + jv_free($2); } | "def" IDENT '(' IDENT ')' ':' Exp ';' Exp { - block body = block_bind(gen_op_block_unbound(CLOSURE_PARAM, $4), block_join($7, gen_op_simple(RET)), OP_IS_CALL_PSEUDO); - $$ = block_bind(gen_op_block_defn(CLOSURE_CREATE, $2, body), $9, OP_IS_CALL_PSEUDO); + block body = block_bind(gen_op_block_unbound(CLOSURE_PARAM, jv_string_value($4)), block_join($7, gen_op_simple(RET)), OP_IS_CALL_PSEUDO); + $$ = block_bind(gen_op_block_defn(CLOSURE_CREATE, jv_string_value($2), body), $9, OP_IS_CALL_PSEUDO); + jv_free($2); + jv_free($4); } | Term "as" '$' IDENT '|' Exp { $$ = gen_op_simple(DUP); block_append(&$$, $1); - block_append(&$$, block_bind(gen_op_var_unbound(STOREV, $4), $6, OP_HAS_VARIABLE)); + block_append(&$$, block_bind(gen_op_var_unbound(STOREV, jv_string_value($4)), $6, OP_HAS_VARIABLE)); + jv_free($4); } | Exp '=' Exp { @@ -129,10 +129,10 @@ Term: $$ = gen_noop(); } | Term '.' IDENT { - $$ = gen_index($1, gen_string($3)); + $$ = gen_index($1, gen_op_const(LOADK, $3)); } | '.' IDENT { - $$ = gen_index(gen_noop(), gen_string($2)); + $$ = gen_index(gen_noop(), gen_op_const(LOADK, $2)); } | /* FIXME: string literals */ Term '[' Exp ']' { @@ -141,8 +141,8 @@ Term '[' Exp ']' { Term '[' ']' { $$ = block_join($1, gen_op_simple(EACH)); } | -NUMBER { - $$ = gen_op_const(LOADK, json_integer($1)); +LITERAL { + $$ = gen_op_const(LOADK, $1); } | '(' Exp ')' { $$ = $2; @@ -151,26 +151,29 @@ NUMBER { $$ = gen_collect($2); } | '[' ']' { - $$ = gen_op_const(LOADK, json_array()); + $$ = gen_op_const(LOADK, jv_array()); } | '{' MkDict '}' { - $$ = gen_subexp(gen_op_const(LOADK, json_object())); + $$ = gen_subexp(gen_op_const(LOADK, jv_object())); block_append(&$$, $2); block_append(&$$, gen_op_simple(POP)); } | '$' IDENT { - $$ = gen_op_var_unbound(LOADV, $2); + $$ = gen_op_var_unbound(LOADV, jv_string_value($2)); + jv_free($2); } | IDENT { - $$ = gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, $1)); + $$ = gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, jv_string_value($1))); + jv_free($1); } | IDENT '(' Exp ')' { $$ = gen_op_call(CALL_1_1, - block_join(gen_op_block_unbound(CLOSURE_REF, $1), + block_join(gen_op_block_unbound(CLOSURE_REF, jv_string_value($1)), block_bind(gen_op_block_defn(CLOSURE_CREATE, "lambda", block_join($3, gen_op_simple(RET))), gen_noop(), OP_IS_CALL_PSEUDO))); + jv_free($1); } MkDict: @@ -184,11 +187,11 @@ MkDictPair MkDictPair : IDENT ':' ExpD { - $$ = gen_dictpair(gen_string($1), $3); + $$ = gen_dictpair(gen_op_const(LOADK, $1), $3); } | IDENT { - $$ = gen_dictpair(gen_string($1), - gen_index(gen_noop(), gen_string($1))); + $$ = gen_dictpair(gen_op_const(LOADK, jv_copy($1)), + gen_index(gen_noop(), gen_op_const(LOADK, $1))); } | '(' Exp ')' ':' ExpD { $$ = gen_dictpair($2, $5); From f72c5ffac0dd03bafd01b73011e8409371429326 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sun, 2 Sep 2012 17:20:13 +0100 Subject: [PATCH 021/284] Move from Jansson to JV - interpreter loop Passes tests, but leaks some memory. --- c/Makefile | 4 +- c/execute.c | 146 ++++++++++++++++++++++----------------------- c/execute.h | 14 ----- c/forkable_stack.h | 6 +- c/frame_layout.h | 8 ++- c/jv.c | 2 +- c/main.c | 13 ++-- 7 files changed, 90 insertions(+), 103 deletions(-) delete mode 100644 c/execute.h diff --git a/c/Makefile b/c/Makefile index bf33acf3..2e598204 100644 --- a/c/Makefile +++ b/c/Makefile @@ -17,8 +17,8 @@ parser.tab.c: parser.y lexer.yy.h bison -W -d parser.y -v --report-file=parser.info parser.tab.h: parser.tab.c -parsertest: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c - $(CC) -o $@ $^ -ljansson +parsertest: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c + $(CC) -o $@ $^ jvtest: jvtest.c jv.c jv_print.c $(CC) -DNO_JANSSON -o $@ $^ diff --git a/c/execute.c b/c/execute.c index 9aa85b29..46779363 100644 --- a/c/execute.c +++ b/c/execute.c @@ -1,10 +1,8 @@ -#include #include #include #include #include - #include "opcode.h" #include "bytecode.h" #include "compile.h" @@ -16,16 +14,16 @@ typedef struct { - json_t* value; + jv value; int pathidx; } stackval; -json_t** pathbuf; +jv* pathbuf; int pathsize; // number of allocated elements - -int path_push(stackval sv, json_t* val) { +// FIXME mem +int path_push(stackval sv, jv val) { int pos = sv.pathidx; assert(pos <= pathsize); assert(pos >= 0); @@ -37,14 +35,15 @@ int path_push(stackval sv, json_t* val) { return pos + 1; } -stackval stackval_replace(stackval value, json_t* newjs) { +stackval stackval_replace(stackval value, jv newjs) { + jv_free(value.value); stackval s = {newjs, value.pathidx}; return s; } // Probably all uses of this function are bugs -stackval stackval_root(json_t* v) { +stackval stackval_root(jv v) { stackval s = {v, 0}; return s; } @@ -63,7 +62,9 @@ void stk_push(stackval val) { stackval stk_pop() { data_stk_elem* s = forkable_stack_peek(&data_stk); stackval sv = s->sv; - forkable_stack_pop(&data_stk); + if (!forkable_stack_pop(&data_stk)) { + sv.value = jv_copy(sv.value); + } return sv; } @@ -118,9 +119,9 @@ static struct closure make_closure(struct forkable_stack* stk, frame_ptr fr, uin #define ON_BACKTRACK(op) ((op)+NUM_OPCODES) -json_t* jq_next() { - json_t* cfunc_input[MAX_CFUNCTION_ARGS] = {0}; - json_t* cfunc_output[MAX_CFUNCTION_ARGS] = {0}; +jv jq_next() { + jv cfunc_input[MAX_CFUNCTION_ARGS]; + jv cfunc_output[MAX_CFUNCTION_ARGS]; assert(!forkable_stack_empty(&frame_stk)); uint16_t* pc = *frame_current_retaddr(&frame_stk); @@ -143,7 +144,7 @@ json_t* jq_next() { } else { param = forkable_stack_peek_next(&data_stk, param); } - json_dumpf(param->sv.value, stdout, JSON_ENCODE_ANY); + jv_dump(jv_copy(param->sv.value)); if (i < opdesc->stack_in-1) printf(" | "); } @@ -159,16 +160,18 @@ json_t* jq_next() { default: assert(0 && "invalid instruction"); case LOADK: { - json_t* v = json_array_get(frame_current_bytecode(&frame_stk)->constants, *pc++); - assert(v); + jv v = jv_array_get(jv_copy(frame_current_bytecode(&frame_stk)->constants), *pc++); + //FIXME assert(v); stack_push(stackval_replace(stack_pop(), v)); break; } case DUP: { stackval v = stack_pop(); + stackval v2 = v; + v2.value = jv_copy(v.value); stack_push(v); - stack_push(v); + stack_push(v2); break; } @@ -181,44 +184,42 @@ json_t* jq_next() { } case POP: { - stack_pop(); + jv_free(stack_pop().value); break; } case APPEND: { // FIXME paths - json_t* v = stack_pop().value; - json_t* array = stack_pop().value; - array = json_copy(array); - json_array_append(array, v); + jv v = stack_pop().value; + jv array = stack_pop().value; + array = jv_array_append(array, v); stack_push(stackval_root(array)); break; } case INSERT: { stackval stktop = stack_pop(); - json_t* v = stack_pop().value; - json_t* k = stack_pop().value; + jv v = stack_pop().value; + jv k = stack_pop().value; stackval objv = stack_pop(); - assert(json_is_string(k)); - assert(json_is_object(objv.value)); - json_t* obj = json_copy(objv.value); - json_object_set(obj, json_string_value(k), v); - assert(json_is_object(obj)); - stack_push(stackval_replace(objv, obj)); + assert(jv_get_kind(k) == JV_KIND_STRING); + assert(jv_get_kind(objv.value) == JV_KIND_OBJECT); + objv.value = jv_object_set(objv.value, k, v); + stack_push(objv); stack_push(stktop); break; } + // FIXME: loadv/storev may do too much copying/freeing case LOADV: { uint16_t level = *pc++; uint16_t v = *pc++; frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); - json_t** var = frame_local_var(fp, v); + jv* var = frame_local_var(fp, v); printf("V%d = ", v); - json_dumpf(*var, stdout, JSON_ENCODE_ANY); + jv_dump(jv_copy(*var)); printf("\n"); - stack_push(stackval_replace(stack_pop(), *var)); + stack_push(stackval_replace(stack_pop(), jv_copy(*var))); break; } @@ -226,43 +227,31 @@ json_t* jq_next() { uint16_t level = *pc++; uint16_t v = *pc++; frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); - json_t** var = frame_local_var(fp, v); + jv* var = frame_local_var(fp, v); stackval val = stack_pop(); printf("V%d = ", v); - json_dumpf(val.value, stdout, JSON_ENCODE_ANY); + jv_dump(jv_copy(val.value)); printf("\n"); + jv_free(*var); *var = val.value; break; } -#if 0 - case DISPLAY: { - stackval sv = stack_pop(); - if (sv.value) { - json_dumpf(sv.value, stdout, JSON_ENCODE_ANY); - } else { - printf("#ERROR"); - } - printf(" - "); - for (int i = 0; i < sv.pathidx; i++) { - printf("/"); - json_dumpf(pathbuf[i], stdout, JSON_ENCODE_ANY); - } - printf("\n"); - return; - } -#endif - case ASSIGN_DBG: { + assert(0); + /* stackval replacement = stack_pop(); stackval path_end = stack_pop(); stackval path_start = stack_pop(); json_t* obj = jv_insert(path_start.value, replacement.value, pathbuf + path_start.pathidx, path_end.pathidx - path_start.pathidx); stack_push(stackval_replace(path_start, obj)); + */ break; } case ASSIGN: { + assert(0); + /* stackval replacement = stack_pop(); stackval path_end = stack_pop(); stackval path_start = stack_pop(); @@ -272,17 +261,18 @@ json_t* jq_next() { frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); json_t** var = frame_local_var(fp, v); *var = jv_insert(*var, replacement.value, pathbuf + path_start.pathidx, path_end.pathidx - path_start.pathidx); + */ break; } case INDEX: { stackval t = stack_pop(); - json_t* k = stack_pop().value; - json_t* v = jv_lookup(t.value, k); - if (v) { + jv k = stack_pop().value; + jv v = jv_lookup(t.value, k); + if (1 /* fixme invalid lookups */) { stackval sv; sv.value = v; - sv.pathidx = path_push(t, k); + sv.pathidx = 0; //FIXME path_push(t, k); stack_push(sv); } else { assert(0 && "bad lookup"); @@ -298,23 +288,24 @@ json_t* jq_next() { } case EACH: - stack_push(stackval_root(json_integer(0))); + stack_push(stackval_root(jv_number(0))); // fallthrough case ON_BACKTRACK(EACH): { - json_t* idxj = stack_pop().value; - int idx = json_integer_value(idxj); + int idx = jv_number_value(stack_pop().value); stackval array = stack_pop(); - if (idx >= json_array_size(array.value)) { + if (idx >= jv_array_length(jv_copy(array.value))) { goto do_backtrack; } else { stack_save(); - stack_push(array); - stack_push(stackval_root(json_integer(idx+1))); + stackval array2 = array; + array2.value = jv_copy(array2.value); + stack_push(array2); + stack_push(stackval_root(jv_number(idx+1))); frame_push_backtrack(&frame_stk, pc - 1); stack_switch(); - stackval sv = {json_array_get(array.value, idx), - path_push(array, json_integer(idx))}; + stackval sv = {jv_array_get(array.value, idx), + path_push(array, jv_number(idx))}; stack_push(sv); } break; @@ -323,7 +314,8 @@ json_t* jq_next() { do_backtrack: case BACKTRACK: { if (forkable_stack_empty(&fork_stk)) { - return 0; + // FIXME: invalid + return jv_null(); } stack_restore(); pc = *frame_current_retaddr(&frame_stk); @@ -347,7 +339,7 @@ json_t* jq_next() { } case YIELD: { - json_t* value = stack_pop().value; + jv value = stack_pop().value; frame_push_backtrack(&frame_stk, pc); return value; } @@ -361,7 +353,8 @@ json_t* jq_next() { struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++]; printf(" call %s\n", func->name); func->fptr(cfunc_input, cfunc_output); - stack_push(stackval_replace(top, cfunc_output[0])); + top.value = cfunc_output[0]; + stack_push(top); break; } @@ -370,15 +363,16 @@ json_t* jq_next() { pc++; // skip nclosures pc++; // skip level stackval top = stack_pop(); - json_t* a = stack_pop().value; - json_t* b = stack_pop().value; + jv a = stack_pop().value; + jv b = stack_pop().value; cfunc_input[0] = top.value; cfunc_input[1] = a; cfunc_input[2] = b; struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++]; printf(" call %s\n", func->name); func->fptr(cfunc_input, cfunc_output); - stack_push(stackval_replace(top, cfunc_output[0])); + top.value = cfunc_output[0]; + stack_push(top); break; } @@ -409,7 +403,7 @@ json_t* jq_next() { } -void jq_init(struct bytecode* bc, json_t* input) { +void jq_init(struct bytecode* bc, jv input) { forkable_stack_init(&data_stk, sizeof(stackval) * 1000); // FIXME: lower this number, see if it breaks forkable_stack_init(&frame_stk, 10240); // FIXME: lower this number, see if it breaks forkable_stack_init(&fork_stk, 10240); // FIXME: lower this number, see if it breaks @@ -421,10 +415,12 @@ void jq_init(struct bytecode* bc, json_t* input) { } void run_program(struct bytecode* bc) { - jq_init(bc, json_loadf(stdin, 0, 0)); - json_t* result; - while ((result = jq_next())) { - json_dumpf(result, stdout, JSON_ENCODE_ANY); + char buf[4096]; + fgets(buf, sizeof(buf), stdin); + jq_init(bc, jv_parse(buf)); + jv result; + while (jv_get_kind(result = jq_next()) != JV_KIND_NULL) { + jv_dump(result); printf("\n"); } printf("end of results\n"); diff --git a/c/execute.h b/c/execute.h deleted file mode 100644 index b978a8e4..00000000 --- a/c/execute.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "opcode.h" -#define MAX_CFUNCTION_PARAM 10 -typedef struct { - json_t* value; - int pathidx; -} stackval; - -typedef void (*cfunction_ptr)(stackval* input, stackval* output); - -struct cfunction { - cfunction_ptr fptr; - const char* name; - opcode callop; -}; diff --git a/c/forkable_stack.h b/c/forkable_stack.h index 971b4ec0..92831989 100644 --- a/c/forkable_stack.h +++ b/c/forkable_stack.h @@ -83,10 +83,14 @@ static void* forkable_stack_peek_next(struct forkable_stack* s, void* top) { } } -static void forkable_stack_pop(struct forkable_stack* s) { +// Returns 1 if the object being popped can not be accessed again +// (i.e. was not saved with a fork) +static int forkable_stack_pop(struct forkable_stack* s) { forkable_stack_check(s); + int finalpop = s->pos < s->savedlimit ? 1 : 0; struct forkable_stack_header* elem = forkable_stack_peek(s); s->pos = elem->next; + return finalpop; } diff --git a/c/frame_layout.h b/c/frame_layout.h index fcbd1dc3..141dbcd8 100644 --- a/c/frame_layout.h +++ b/c/frame_layout.h @@ -1,7 +1,6 @@ #ifndef FRAME_LAYOUT_H #include "forkable_stack.h" #include "bytecode.h" -#include struct closure { struct bytecode* bc; @@ -18,7 +17,7 @@ typedef union frame_elem { FORKABLE_STACK_HEADER; struct continuation cont; struct closure closure; - json_t* jsonval; + jv jsonval; } *frame_ptr; /* @@ -43,7 +42,7 @@ static struct closure* frame_closure_arg(frame_ptr fr, int closure) { return &fr[2+closure].closure; } -static json_t** frame_local_var(frame_ptr fr, int var) { +static jv* frame_local_var(frame_ptr fr, int var) { assert(var >= 0); assert(var < frame_self(fr)->bc->nlocals); return &fr[2 + frame_self(fr)->bc->nclosures + var].jsonval; @@ -85,6 +84,9 @@ static frame_ptr frame_push(struct forkable_stack* stk, struct closure cl, uint1 cc->bc = cl.bc; cc->env = cl.env; cc->retaddr = retaddr; + for (int i=0; inlocals; i++) { + *frame_local_var(fp, i) = jv_null(); + } return fp; } diff --git a/c/jv.c b/c/jv.c index 7944d642..03954314 100644 --- a/c/jv.c +++ b/c/jv.c @@ -239,7 +239,7 @@ jv jv_array_concat(jv a, jv b) { assert(jv_get_kind(b) == JV_KIND_ARRAY); // FIXME: could be much faster - for (int i=0; i Date: Sun, 2 Sep 2012 17:24:17 +0100 Subject: [PATCH 022/284] Clean up build a little and add .gitignore. --- .gitignore | 12 ++++++++++++ c/Makefile | 6 +++--- c/{jvtest.c => jv_test.c} | 0 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 .gitignore rename c/{jvtest.c => jv_test.c} (100%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..130e618d --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +*.o +*~ + +# Autogenerated by flex/bison +lexer.yy.* +parser.tab.* +parser.info + +# Test binaries +jv_test +jv_parse +parsertest \ No newline at end of file diff --git a/c/Makefile b/c/Makefile index 2e598204..d437b143 100644 --- a/c/Makefile +++ b/c/Makefile @@ -20,13 +20,13 @@ parser.tab.h: parser.tab.c parsertest: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c $(CC) -o $@ $^ -jvtest: jvtest.c jv.c jv_print.c +jv_test: jv_test.c jv.c jv_print.c jv_dtoa.c $(CC) -DNO_JANSSON -o $@ $^ jv_parse: jv_parse.c jv.c jv_print.c jv_dtoa.c $(CC) -DNO_JANSSON -o $@ $^ -DJV_PARSE_MAIN -test: jvtest - valgrind --error-exitcode=1 -q --leak-check=full ./jvtest +test: jv_test + valgrind --error-exitcode=1 -q --leak-check=full ./jv_test diff --git a/c/jvtest.c b/c/jv_test.c similarity index 100% rename from c/jvtest.c rename to c/jv_test.c From 4f747e6fffa2e80a6d62fac66eb88521e9cfc602 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sun, 2 Sep 2012 21:45:27 +0100 Subject: [PATCH 023/284] Move from Jansson to JV - proper freeing of memory A few more tests, now passes valgrind. --- c/builtin.c | 5 +++++ c/execute.c | 39 +++++++++++++++++++++++++++++++-------- c/forkable_stack.h | 23 +++++++++++++++++------ c/frame_layout.h | 13 +++++++++++++ c/jv.c | 33 ++++++++++++++++++++++++++++++++- c/jv.h | 2 ++ c/main.c | 2 ++ c/testdata | 45 +++++++++++++++++++++++++++++++++++++++------ 8 files changed, 141 insertions(+), 21 deletions(-) diff --git a/c/builtin.c b/c/builtin.c index 0252566a..d468e7b7 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -1,15 +1,18 @@ #include "builtin.h" static void f_false(jv input[], jv output[]) { + jv_free(input[0]); output[0] = jv_false(); } static void f_true(jv input[], jv output[]) { + jv_free(input[0]); output[0] = jv_true(); } static void f_plus(jv input[], jv output[]) { + jv_free(input[0]); jv a = input[2]; jv b = input[1]; if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { @@ -19,6 +22,8 @@ static void f_plus(jv input[], jv output[]) { output[0] = jv_array_concat(a, b); } else { output[0] = jv_string("wtf gaize"); + jv_free(a); + jv_free(b); } } diff --git a/c/execute.c b/c/execute.c index 46779363..49cc1835 100644 --- a/c/execute.c +++ b/c/execute.c @@ -24,6 +24,7 @@ int pathsize; // number of allocated elements // FIXME mem int path_push(stackval sv, jv val) { + return 0; int pos = sv.pathidx; assert(pos <= pathsize); assert(pos >= 0); @@ -54,17 +55,18 @@ typedef struct { stackval sv; } data_stk_elem; -void stk_push(stackval val) { +void stack_push(stackval val) { data_stk_elem* s = forkable_stack_push(&data_stk, sizeof(data_stk_elem)); s->sv = val; } -stackval stk_pop() { +stackval stack_pop() { data_stk_elem* s = forkable_stack_peek(&data_stk); stackval sv = s->sv; - if (!forkable_stack_pop(&data_stk)) { + if (!forkable_stack_pop_will_free(&data_stk)) { sv.value = jv_copy(sv.value); } + forkable_stack_pop(&data_stk); return sv; } @@ -92,6 +94,14 @@ void stack_switch() { } void stack_restore(){ + while (!forkable_stack_empty(&data_stk) && + forkable_stack_pop_will_free(&data_stk)) { + jv_free(stack_pop().value); + } + while (!forkable_stack_empty(&frame_stk) && + forkable_stack_pop_will_free(&frame_stk)) { + frame_pop(&frame_stk); + } struct forkpoint* fork = forkable_stack_peek(&fork_stk); forkable_stack_restore(&data_stk, &fork->saved_data_stack); forkable_stack_restore(&frame_stk, &fork->saved_call_stack); @@ -114,9 +124,6 @@ static struct closure make_closure(struct forkable_stack* stk, frame_ptr fr, uin } -#define stack_push stk_push -#define stack_pop stk_pop - #define ON_BACKTRACK(op) ((op)+NUM_OPCODES) jv jq_next() { @@ -142,10 +149,12 @@ jv jq_next() { if (i == 0) { param = forkable_stack_peek(&data_stk); } else { + printf(" | "); param = forkable_stack_peek_next(&data_stk, param); } + if (!param) break; jv_dump(jv_copy(param->sv.value)); - if (i < opdesc->stack_in-1) printf(" | "); + printf("<%d>", jv_get_refcnt(param->sv.value)); } if (backtracking) { @@ -294,6 +303,7 @@ jv jq_next() { int idx = jv_number_value(stack_pop().value); stackval array = stack_pop(); if (idx >= jv_array_length(jv_copy(array.value))) { + jv_free(array.value); goto do_backtrack; } else { stack_save(); @@ -314,7 +324,7 @@ jv jq_next() { do_backtrack: case BACKTRACK: { if (forkable_stack_empty(&fork_stk)) { - // FIXME: invalid + // FIXME: invalid jv value return jv_null(); } stack_restore(); @@ -407,6 +417,7 @@ void jq_init(struct bytecode* bc, jv input) { forkable_stack_init(&data_stk, sizeof(stackval) * 1000); // FIXME: lower this number, see if it breaks forkable_stack_init(&frame_stk, 10240); // FIXME: lower this number, see if it breaks forkable_stack_init(&fork_stk, 10240); // FIXME: lower this number, see if it breaks + stack_save(); stack_push(stackval_root(input)); struct closure top = {bc, -1}; @@ -414,6 +425,18 @@ void jq_init(struct bytecode* bc, jv input) { frame_push_backtrack(&frame_stk, bc->code); } +void jq_teardown() { + while (!forkable_stack_empty(&fork_stk)) { + stack_restore(); + } + assert(forkable_stack_empty(&fork_stk)); + assert(forkable_stack_empty(&data_stk)); + assert(forkable_stack_empty(&frame_stk)); + forkable_stack_free(&fork_stk); + forkable_stack_free(&data_stk); + forkable_stack_free(&frame_stk); +} + void run_program(struct bytecode* bc) { char buf[4096]; fgets(buf, sizeof(buf), stdin); diff --git a/c/forkable_stack.h b/c/forkable_stack.h index 92831989..3128a6ca 100644 --- a/c/forkable_stack.h +++ b/c/forkable_stack.h @@ -46,6 +46,13 @@ static void forkable_stack_init(struct forkable_stack* s, size_t sz) { forkable_stack_check(s); } +static void forkable_stack_free(struct forkable_stack* s) { + assert(forkable_stack_empty(s)); + assert(s->savedlimit == s->length); + free(s->stk); + s->stk = 0; +} + static void* forkable_stack_push(struct forkable_stack* s, size_t size) { forkable_stack_check(s); int curr = s->pos < s->savedlimit ? s->pos : s->savedlimit; @@ -83,14 +90,16 @@ static void* forkable_stack_peek_next(struct forkable_stack* s, void* top) { } } -// Returns 1 if the object being popped can not be accessed again -// (i.e. was not saved with a fork) -static int forkable_stack_pop(struct forkable_stack* s) { +// Returns 1 if the next forkable_stack_pop will permanently remove an +// object from the stack (i.e. the top object was not saved with a fork) +static int forkable_stack_pop_will_free(struct forkable_stack* s) { + return s->pos < s->savedlimit ? 1 : 0; +} + +static void forkable_stack_pop(struct forkable_stack* s) { forkable_stack_check(s); - int finalpop = s->pos < s->savedlimit ? 1 : 0; struct forkable_stack_header* elem = forkable_stack_peek(s); s->pos = elem->next; - return finalpop; } @@ -114,12 +123,14 @@ static void forkable_stack_switch(struct forkable_stack* s, struct forkable_stac int curr_limit = s->savedlimit; if (curr_pos < curr_limit) s->savedlimit = curr_pos; - state->prevlimit = curr_limit; + //state->prevlimit = curr_limit; FIXME clean up forkable_stack_check(s); } static void forkable_stack_restore(struct forkable_stack* s, struct forkable_stack_state* state) { forkable_stack_check(s); + assert(s->savedlimit <= state->prevpos); + assert(s->savedlimit <= state->prevlimit); s->pos = state->prevpos; s->savedlimit = state->prevlimit; forkable_stack_check(s); diff --git a/c/frame_layout.h b/c/frame_layout.h index 141dbcd8..d2218e92 100644 --- a/c/frame_layout.h +++ b/c/frame_layout.h @@ -11,6 +11,8 @@ struct continuation { struct bytecode* bc; stack_idx env; uint16_t* retaddr; + // FIXME: probably not necessary as a separate field + int is_backtrack_frame; }; typedef union frame_elem { @@ -84,6 +86,7 @@ static frame_ptr frame_push(struct forkable_stack* stk, struct closure cl, uint1 cc->bc = cl.bc; cc->env = cl.env; cc->retaddr = retaddr; + cc->is_backtrack_frame = 0; for (int i=0; inlocals; i++) { *frame_local_var(fp, i) = jv_null(); } @@ -93,12 +96,22 @@ static frame_ptr frame_push(struct forkable_stack* stk, struct closure cl, uint1 static frame_ptr frame_push_backtrack(struct forkable_stack* stk, uint16_t* retaddr) { struct continuation cc = *frame_self(frame_current(stk)); frame_ptr fp = forkable_stack_push(stk, sizeof(union frame_elem) * 2); + assert(!cc.is_backtrack_frame); + cc.is_backtrack_frame = 1; cc.retaddr = retaddr; *frame_self(fp) = cc; return fp; } static void frame_pop(struct forkable_stack* stk) { + frame_ptr fp = frame_current(stk); + if (forkable_stack_pop_will_free(stk) && + !frame_self(fp)->is_backtrack_frame) { + int nlocals = frame_self(fp)->bc->nlocals; + for (int i=0; i #include #include +#include #include #include "jv.h" @@ -641,6 +642,21 @@ static int jvp_object_length(jv_complex* object) { return n; } +static int jvp_object_equal(jv_complex* o1, jv_complex* o2) { + int len2 = jvp_object_length(o2); + int len1 = 0; + for (int i=0; istring) continue; + jv* slot2 = jvp_object_read(o2, slot->string); + if (!slot2) return 0; + // FIXME: do less refcounting here + if (!jv_equal(jv_copy(slot->value), jv_copy(*slot2))) return 0; + len1++; + } + return len1 == len2; +} + /* * Objects (public interface) */ @@ -752,6 +768,17 @@ void jv_free(jv j) { } } +int jv_get_refcnt(jv j) { + switch (jv_get_kind(j)) { + case JV_KIND_ARRAY: + case JV_KIND_STRING: + case JV_KIND_OBJECT: + return j.val.complex.ptr->count; + default: + return 1; + } +} + /* * Higher-level operations */ @@ -772,7 +799,11 @@ int jv_equal(jv a, jv b) { case JV_KIND_STRING: { r = jvp_string_equal(&a.val.complex, &b.val.complex); break; - } + } + case JV_KIND_OBJECT: { + r = jvp_object_equal(&a.val.complex, &b.val.complex); + break; + } default: r = 1; break; diff --git a/c/jv.h b/c/jv.h index 7696b03b..c03967b1 100644 --- a/c/jv.h +++ b/c/jv.h @@ -82,6 +82,8 @@ jv jv_object_iter_key(jv, int); jv jv_object_iter_value(jv, int); +int jv_get_refcnt(jv); + void jv_dump(jv); jv jv_parse(const char* string); diff --git a/c/main.c b/c/main.c index 077268b4..4d4081f4 100644 --- a/c/main.c +++ b/c/main.c @@ -8,6 +8,7 @@ block compile(const char* str); void jq_init(struct bytecode* bc, jv value); jv jq_next(); +void jq_teardown(); void run_program(struct bytecode* bc); @@ -67,6 +68,7 @@ void run_tests() { pass = 0; }*/ } + jq_teardown(); bytecode_free(bc); tests++; passed+=pass; diff --git a/c/testdata b/c/testdata index 95e40781..2cdaaa5f 100644 --- a/c/testdata +++ b/c/testdata @@ -76,6 +76,27 @@ null 2 3 +1,1 +[] +1 +1 + +[.] +[2] +[[2]] + +[[2]] +[3] +[[2]] + +[{}] +[2] +[{}] + +[.[]] +["a"] +["a"] + [(.,1),((.,.[]),(2,3))] ["a","b"] [["a","b"],1,["a","b"],"a","b",2,3] @@ -118,7 +139,7 @@ null 1+1 null -2.0 +2 .+4 15 @@ -143,11 +164,17 @@ def f: (1000,2000); f 1000 2000 -# test backtracking through function calls and returns -# this test is *evil* -[[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | g; f[0] | [f][0][1] | f] -"woo, testing!" -[[110.0, 130.0], [210.0, 130.0], [110.0, 230.0], [210.0, 230.0], [120.0, 160.0], [220.0, 160.0], [120.0, 260.0], [220.0, 260.0]] +([1,2] + [4,5]) +[1,2,3] +[1,2,4,5] + +true +[1] +true + +[1,2,3] +[5,6] +[1,2,3] def f(x): x | x; f([.], . + [42]) [1,2,3] @@ -160,3 +187,9 @@ def f(x): x | x; f([.], . + [42]) def id(x):x; 2000 as $x | def f(x):1 as $x | id([$x, x, x]); def g(x): 100 as $x | f($x,$x+x); g($x) "more testing" [1,100,2100.0,100,2100.0] + +# test backtracking through function calls and returns +# this test is *evil* +[[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | g; f[0] | [f][0][1] | f] +"woo, testing!" +[[110.0, 130.0], [210.0, 130.0], [110.0, 230.0], [210.0, 230.0], [120.0, 160.0], [220.0, 160.0], [120.0, 260.0], [220.0, 260.0]] From e3710c0d1f0dd9900dbe88a4b3b036939da17f51 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sun, 2 Sep 2012 22:08:36 +0100 Subject: [PATCH 024/284] Fix behaviour of stack at program termination. --- c/execute.c | 29 ++++++++++++++--------------- c/main.c | 4 +++- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/c/execute.c b/c/execute.c index 49cc1835..c22d1df3 100644 --- a/c/execute.c +++ b/c/execute.c @@ -93,7 +93,7 @@ void stack_switch() { forkable_stack_switch(&frame_stk, &fork->saved_call_stack); } -void stack_restore(){ +int stack_restore(){ while (!forkable_stack_empty(&data_stk) && forkable_stack_pop_will_free(&data_stk)) { jv_free(stack_pop().value); @@ -102,10 +102,15 @@ void stack_restore(){ forkable_stack_pop_will_free(&frame_stk)) { frame_pop(&frame_stk); } - struct forkpoint* fork = forkable_stack_peek(&fork_stk); - forkable_stack_restore(&data_stk, &fork->saved_data_stack); - forkable_stack_restore(&frame_stk, &fork->saved_call_stack); - forkable_stack_pop(&fork_stk); + if (forkable_stack_empty(&fork_stk)) { + return 0; + } else { + struct forkpoint* fork = forkable_stack_peek(&fork_stk); + forkable_stack_restore(&data_stk, &fork->saved_data_stack); + forkable_stack_restore(&frame_stk, &fork->saved_call_stack); + forkable_stack_pop(&fork_stk); + return 1; + } } static struct closure make_closure(struct forkable_stack* stk, frame_ptr fr, uint16_t* pc) { @@ -323,11 +328,10 @@ jv jq_next() { do_backtrack: case BACKTRACK: { - if (forkable_stack_empty(&fork_stk)) { + if (!stack_restore()) { // FIXME: invalid jv value return jv_null(); } - stack_restore(); pc = *frame_current_retaddr(&frame_stk); frame_pop(&frame_stk); backtracking = 1; @@ -417,7 +421,6 @@ void jq_init(struct bytecode* bc, jv input) { forkable_stack_init(&data_stk, sizeof(stackval) * 1000); // FIXME: lower this number, see if it breaks forkable_stack_init(&frame_stk, 10240); // FIXME: lower this number, see if it breaks forkable_stack_init(&fork_stk, 10240); // FIXME: lower this number, see if it breaks - stack_save(); stack_push(stackval_root(input)); struct closure top = {bc, -1}; @@ -426,9 +429,8 @@ void jq_init(struct bytecode* bc, jv input) { } void jq_teardown() { - while (!forkable_stack_empty(&fork_stk)) { - stack_restore(); - } + while (stack_restore()) {} + assert(forkable_stack_empty(&fork_stk)); assert(forkable_stack_empty(&data_stk)); assert(forkable_stack_empty(&frame_stk)); @@ -447,8 +449,5 @@ void run_program(struct bytecode* bc) { printf("\n"); } printf("end of results\n"); - - //assert(frame == stack_top_frame(bc->framesize)); - //stk_pop_frame(bc->framesize); - //assert(stackpos == 0); + jq_teardown(); } diff --git a/c/main.c b/c/main.c index 4d4081f4..5cdc7d62 100644 --- a/c/main.c +++ b/c/main.c @@ -81,9 +81,11 @@ int main(int argc, char* argv[]) { if (argc == 1) { run_tests(); return 0; } block blk = compile(argv[1]); block_append(&blk, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK))); - struct bytecode* bc = block_compile(gen_cbinding(&builtins, blk)); + blk = gen_cbinding(&builtins, blk); + struct bytecode* bc = block_compile(blk); block_free(blk); dump_disassembly(0, bc); printf("\n"); run_program(bc); + bytecode_free(bc); } From 22ffc0fdfce541ec3f2a6a5166db64f2c752d91d Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sun, 2 Sep 2012 22:24:27 +0100 Subject: [PATCH 025/284] Mark a constant array const in jvp_dtoa.c --- c/jv_dtoa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/jv_dtoa.c b/c/jv_dtoa.c index 1388943b..c3132024 100644 --- a/c/jv_dtoa.c +++ b/c/jv_dtoa.c @@ -867,7 +867,7 @@ pow5mult { Bigint *b1, *p5, *p51; int i; - static int p05[3] = { 5, 25, 125 }; + static const int p05[3] = { 5, 25, 125 }; if ((i = k & 3)) b = multadd(C, b, p05[i-1], 0); From 52487ff81258ed65992065a2a6ffa1286064f6eb Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 3 Sep 2012 01:12:42 +0100 Subject: [PATCH 026/284] Remove globals from parser, use explicit structure. --- c/jv_parse.c | 233 +++++++++++++++++++++++++++------------------------ c/jv_parse.h | 20 +++++ 2 files changed, 142 insertions(+), 111 deletions(-) create mode 100644 c/jv_parse.h diff --git a/c/jv_parse.c b/c/jv_parse.c index 26c2cc38..2c2da395 100644 --- a/c/jv_parse.c +++ b/c/jv_parse.c @@ -2,10 +2,7 @@ #include #include "jv.h" #include "jv_dtoa.h" -jv stack[1000]; -int stackpos = 0; -jv next; -int hasnext; +#include "jv_parse.h" typedef const char* presult; @@ -16,55 +13,78 @@ typedef const char* presult; #define pfunc presult #endif +void jv_parser_init(struct jv_parser* p) { + p->stack = 0; + p->stacklen = p->stackpos = 0; + p->hasnext = 0; + p->next = jv_null(); //FIXME: jv_invalid + p->tokenbuf = 0; + p->tokenlen = p->tokenpos = 0; + p->st = JV_PARSER_NORMAL; + jvp_dtoa_context_init(&p->dtoa); +} +void jv_parser_free(struct jv_parser* p) { + if (p->hasnext) jv_free(p->next); + free(p->stack); + free(p->tokenbuf); + jvp_dtoa_context_free(&p->dtoa); +} -pfunc value(jv val) { - if (hasnext) return "Expected separator between values"; - hasnext = 1; - next = val; +static pfunc value(struct jv_parser* p, jv val) { + if (p->hasnext) return "Expected separator between values"; + p->hasnext = 1; + p->next = val; return 0; } -void push(jv v) { - stack[stackpos++] = v; +static void push(struct jv_parser* p, jv v) { + assert(p->stackpos <= p->stacklen); + if (p->stackpos == p->stacklen) { + p->stacklen = p->stacklen * 2 + 10; + p->stack = realloc(p->stack, p->stacklen * sizeof(jv)); + } + assert(p->stackpos < p->stacklen); + p->stack[p->stackpos++] = v; } -pfunc token(char ch) { +static pfunc token(struct jv_parser* p, char ch) { switch (ch) { case '[': - if (hasnext) return "Expected separator between values"; - push(jv_array()); + if (p->hasnext) return "Expected separator between values"; + push(p, jv_array()); break; case '{': - if (hasnext) return "Expected separator between values"; - push(jv_object()); + if (p->hasnext) return "Expected separator between values"; + push(p, jv_object()); break; case ':': - if (!hasnext) + if (!p->hasnext) return "Expected string key before ':'"; - if (stackpos == 0 || jv_get_kind(stack[stackpos-1]) != JV_KIND_OBJECT) + if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) return "':' not as part of an object"; - if (jv_get_kind(next) != JV_KIND_STRING) + if (jv_get_kind(p->next) != JV_KIND_STRING) return "Object keys must be strings"; - push(next); - hasnext = 0; + push(p, p->next); + p->hasnext = 0; break; case ',': - if (!hasnext) + if (!p->hasnext) return "Expected value before ','"; - if (stackpos == 0) + if (p->stackpos == 0) return "',' not as part of an object or array"; - if (jv_get_kind(stack[stackpos-1]) == JV_KIND_ARRAY) { - stack[stackpos-1] = jv_array_append(stack[stackpos-1], next); - hasnext = 0; - } else if (jv_get_kind(stack[stackpos-1]) == JV_KIND_STRING) { - assert(stackpos > 1 && jv_get_kind(stack[stackpos-2]) == JV_KIND_OBJECT); - stack[stackpos-2] = jv_object_set(stack[stackpos-2], stack[stackpos-1], next); - stackpos--; - hasnext = 0; + if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_ARRAY) { + p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); + p->hasnext = 0; + } else if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_STRING) { + assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); + p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], + p->stack[p->stackpos-1], p->next); + p->stackpos--; + p->hasnext = 0; } else { // this case hits on input like {"a", "b"} return "Objects must consist of key:value pairs"; @@ -72,54 +92,57 @@ pfunc token(char ch) { break; case ']': - if (stackpos == 0 || jv_get_kind(stack[stackpos-1]) != JV_KIND_ARRAY) + if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_ARRAY) return "Unmatched ']'"; - if (hasnext) { - stack[stackpos-1] = jv_array_append(stack[stackpos-1], next); - hasnext = 0; + if (p->hasnext) { + p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); + p->hasnext = 0; } else { - if (jv_array_length(jv_copy(stack[stackpos-1])) != 0) { + if (jv_array_length(jv_copy(p->stack[p->stackpos-1])) != 0) { // this case hits on input like [1,2,3,] return "Expected another array element"; } } - hasnext = 1; - next = stack[--stackpos]; + p->hasnext = 1; + p->next = p->stack[--p->stackpos]; break; case '}': - if (stackpos == 0) + if (p->stackpos == 0) return "Unmatched '}'"; - if (hasnext) { - if (jv_get_kind(stack[stackpos-1]) != JV_KIND_STRING) + if (p->hasnext) { + if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_STRING) return "Objects must consist of key:value pairs"; - assert(stackpos > 1 && jv_get_kind(stack[stackpos-2]) == JV_KIND_OBJECT); - stack[stackpos-2] = jv_object_set(stack[stackpos-2], stack[stackpos-1], next); - stackpos--; - hasnext = 0; + assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); + p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], + p->stack[p->stackpos-1], p->next); + p->stackpos--; + p->hasnext = 0; } else { - if (jv_get_kind(stack[stackpos-1]) != JV_KIND_OBJECT) + if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) return "Unmatched '}'"; - if (jv_object_length(jv_copy(stack[stackpos-1])) != 0) + if (jv_object_length(jv_copy(p->stack[p->stackpos-1])) != 0) return "Expected another key-value pair"; } - hasnext = 1; - next = stack[--stackpos]; + p->hasnext = 1; + p->next = p->stack[--p->stackpos]; break; } return 0; } -char tokenbuf[1000]; -int tokenpos; -struct dtoa_context dtoa; - -void tokenadd(char c) { - tokenbuf[tokenpos++] = c; +static void tokenadd(struct jv_parser* p, char c) { + assert(p->tokenpos <= p->tokenlen); + if (p->tokenpos == p->tokenlen) { + p->tokenlen = p->tokenlen*2 + 256; + p->tokenbuf = realloc(p->tokenbuf, p->tokenlen); + } + assert(p->tokenpos < p->tokenlen); + p->tokenbuf[p->tokenpos++] = c; } -int unhex4(char* hex) { +static int unhex4(char* hex) { int r = 0; for (int i=0; i<4; i++) { char c = *hex++; @@ -133,7 +156,7 @@ int unhex4(char* hex) { return r; } -int utf8_encode(int codepoint, char* out) { +static int utf8_encode(int codepoint, char* out) { assert(codepoint >= 0 && codepoint <= 0x10FFFF); char* start = out; if (codepoint <= 0x7F) { @@ -154,10 +177,10 @@ int utf8_encode(int codepoint, char* out) { return out - start; } -pfunc found_string() { - char* in = tokenbuf; - char* out = tokenbuf; - char* end = tokenbuf + tokenpos; +static pfunc found_string(struct jv_parser* p) { + char* in = p->tokenbuf; + char* out = p->tokenbuf; + char* end = p->tokenbuf + p->tokenpos; while (in < end) { char c = *in++; @@ -203,38 +226,38 @@ pfunc found_string() { *out++ = c; } } - TRY(value(jv_string_sized(tokenbuf, out - tokenbuf))); - tokenpos=0; + TRY(value(p, jv_string_sized(p->tokenbuf, out - p->tokenbuf))); + p->tokenpos = 0; return 0; } -pfunc check_literal() { - if (tokenpos == 0) return 0; +static pfunc check_literal(struct jv_parser* p) { + if (p->tokenpos == 0) return 0; const char* pattern = 0; int plen; jv v; - switch (tokenbuf[0]) { + switch (p->tokenbuf[0]) { case 't': pattern = "true"; plen = 4; v = jv_true(); break; case 'f': pattern = "false"; plen = 5; v = jv_false(); break; case 'n': pattern = "null"; plen = 4; v = jv_null(); break; } if (pattern) { - if (tokenpos != plen) return "Invalid literal"; + if (p->tokenpos != plen) return "Invalid literal"; for (int i=0; itokenbuf[i] != pattern[i]) return "Invalid literal"; - TRY(value(v)); + TRY(value(p, v)); } else { // FIXME: better parser - tokenbuf[tokenpos] = 0; // FIXME: invalid + p->tokenbuf[p->tokenpos] = 0; // FIXME: invalid char* end = 0; - double d = jvp_strtod(&dtoa, tokenbuf, &end); + double d = jvp_strtod(&p->dtoa, p->tokenbuf, &end); if (end == 0 || *end != 0) return "Invalid numeric literal"; - TRY(value(jv_number(d))); + TRY(value(p, jv_number(d))); } - tokenpos=0; + p->tokenpos = 0; return 0; } @@ -246,7 +269,7 @@ typedef enum { INVALID } chclass; -chclass classify(char c) { +static chclass classify(char c) { switch (c) { case ' ': case '\t': @@ -268,91 +291,79 @@ chclass classify(char c) { } -enum state { - NORMAL, - STRING, - STRING_ESCAPE -}; -enum state st = NORMAL; -pfunc scan(char ch) { - if (st == NORMAL) { +static pfunc scan(struct jv_parser* p, char ch) { + if (p->st == JV_PARSER_NORMAL) { chclass cls = classify(ch); if (cls != LITERAL) { - TRY(check_literal()); + TRY(check_literal(p)); } switch (cls) { case LITERAL: - tokenadd(ch); + tokenadd(p, ch); break; case WHITESPACE: break; case QUOTE: - st = STRING; + p->st = JV_PARSER_STRING; break; case STRUCTURE: - TRY(token(ch)); + TRY(token(p, ch)); break; case INVALID: return "Invalid character"; } } else { - if (ch == '"' && st == STRING) { - TRY(found_string()); - st = NORMAL; + if (ch == '"' && p->st == JV_PARSER_STRING) { + TRY(found_string(p)); + p->st = JV_PARSER_NORMAL; } else { - tokenadd(ch); - if (ch == '\\' && st == STRING) { - st = STRING_ESCAPE; + tokenadd(p, ch); + if (ch == '\\' && p->st == JV_PARSER_STRING) { + p->st = JV_PARSER_STRING_ESCAPE; } else { - st = STRING; + p->st = JV_PARSER_STRING; } } } return 0; } -pfunc finish() { - assert(st == NORMAL); - TRY(check_literal()); +static pfunc finish(struct jv_parser* p) { + if (p->st != JV_PARSER_NORMAL) + return "Unfinished string"; + TRY(check_literal(p)); - if (stackpos != 0) + if (p->stackpos != 0) return "Unfinished JSON term"; // this will happen on the empty string - if (!hasnext) + if (!p->hasnext) return "Expected JSON value"; return 0; } jv jv_parse(const char* string) { - jvp_dtoa_context_init(&dtoa); + struct jv_parser parser; + jv_parser_init(&parser); const char* p = string; char ch; while ((ch = *p++)) { - presult msg = scan(ch); + presult msg = scan(&parser, ch); if (msg){ printf("ERROR: %s (parsing [%s])\n", msg, string); return jv_null(); } } - presult msg = finish(); + presult msg = finish(&parser); if (msg) { printf("ERROR: %s (parsing [%s])\n", msg, string); return jv_null(); } - jvp_dtoa_context_free(&dtoa); - hasnext = 0; - return next; + jv value = jv_copy(parser.next); + jv_parser_free(&parser); + return value; } -#if JV_PARSE_MAIN -int main(int argc, char* argv[]) { - assert(argc == 2); - jv_dump(jv_parse(argv[1])); - printf("\n"); - return 0; -} -#endif diff --git a/c/jv_parse.h b/c/jv_parse.h new file mode 100644 index 00000000..4dddcf6f --- /dev/null +++ b/c/jv_parse.h @@ -0,0 +1,20 @@ + +struct jv_parser { + jv* stack; + int stackpos; + int stacklen; + jv next; + int hasnext; + + char* tokenbuf; + int tokenpos; + int tokenlen; + + struct dtoa_context dtoa; + + enum { + JV_PARSER_NORMAL, + JV_PARSER_STRING, + JV_PARSER_STRING_ESCAPE + } st; +}; From 6041fd76613b287ccda3de58829a9e0f98b91f17 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 3 Sep 2012 13:36:12 +0100 Subject: [PATCH 027/284] Literal strings and better literal numbers. --- c/jv.h | 2 +- c/jv_parse.c | 15 +++++++++++---- c/lexer.l | 8 +++++++- c/parser.y | 4 ++++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/c/jv.h b/c/jv.h index c03967b1..8fbc77ab 100644 --- a/c/jv.h +++ b/c/jv.h @@ -86,7 +86,7 @@ int jv_get_refcnt(jv); void jv_dump(jv); jv jv_parse(const char* string); - +jv jv_parse_sized(const char* string, int length); diff --git a/c/jv_parse.c b/c/jv_parse.c index 2c2da395..1f6a20aa 100644 --- a/c/jv_parse.c +++ b/c/jv_parse.c @@ -1,5 +1,6 @@ #include #include +#include #include "jv.h" #include "jv_dtoa.h" #include "jv_parse.h" @@ -345,25 +346,31 @@ static pfunc finish(struct jv_parser* p) { return 0; } -jv jv_parse(const char* string) { +jv jv_parse_sized(const char* string, int length) { + printf("'%s' [%d]", string, length); struct jv_parser parser; jv_parser_init(&parser); const char* p = string; char ch; - while ((ch = *p++)) { + while (p < string + length) { + ch = *p++; presult msg = scan(&parser, ch); if (msg){ - printf("ERROR: %s (parsing [%s])\n", msg, string); + printf("ERROR: %s (parsing '%s')\n", msg, string); return jv_null(); } } presult msg = finish(&parser); if (msg) { - printf("ERROR: %s (parsing [%s])\n", msg, string); + printf("ERROR: %s (parsing '%s')\n", msg, string); return jv_null(); } jv value = jv_copy(parser.next); jv_parser_free(&parser); return value; } + +jv jv_parse(const char* string) { + return jv_parse_sized(string, strlen(string)); +} diff --git a/c/lexer.l b/c/lexer.l index 34253b01..550ad85d 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -15,9 +15,15 @@ "|=" { return SETPIPE; } "."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];} -[[:digit:]]+ { yylval->literal = jv_number((double)atoi(yytext)); return LITERAL;} +\"(\\.|[^\\"])*\" | +[+-]?[0-9.]+([eE][+-]?[0-9]+)? { + yylval->literal = jv_parse_sized(yytext, yyleng); return LITERAL; +} + [[:alnum:]]+ { yylval->literal = jv_string(yytext); return IDENT;} + [ \n\t]+ {} + %% /* perhaps these should be calls... */ /* diff --git a/c/parser.y b/c/parser.y index 14a338a7..36292453 100644 --- a/c/parser.y +++ b/c/parser.y @@ -189,6 +189,10 @@ MkDictPair : IDENT ':' ExpD { $$ = gen_dictpair(gen_op_const(LOADK, $1), $3); } +| LITERAL ':' ExpD { + assert(jv_get_kind($1) == JV_KIND_STRING); + $$ = gen_dictpair(gen_op_const(LOADK, $1), $3); + } | IDENT { $$ = gen_dictpair(gen_op_const(LOADK, jv_copy($1)), gen_index(gen_noop(), gen_op_const(LOADK, $1))); From cf004c2b3a24ec72cbd86a354b4bf39700c7ff43 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 3 Sep 2012 13:57:53 +0100 Subject: [PATCH 028/284] Modify number formatting so that 1e-3 renders as 0.001, not .001 --- c/jv_dtoa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/c/jv_dtoa.c b/c/jv_dtoa.c index c3132024..2c27c880 100644 --- a/c/jv_dtoa.c +++ b/c/jv_dtoa.c @@ -4247,6 +4247,7 @@ jvp_dtoa *b = 0; } else if (decpt <= 0) { + *b++ = '0'; *b++ = '.'; for(; decpt < 0; decpt++) *b++ = '0'; From d8fad1ed9bbb53ca2c5c2c101664b235a6b55c0c Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 3 Sep 2012 15:32:50 +0100 Subject: [PATCH 029/284] Disallow a + before numbers (makes parsing easier, agrees with JSON) --- c/lexer.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/lexer.l b/c/lexer.l index 550ad85d..4acb026a 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -16,7 +16,7 @@ "."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];} \"(\\.|[^\\"])*\" | -[+-]?[0-9.]+([eE][+-]?[0-9]+)? { +-?[0-9.]+([eE][+-]?[0-9]+)? { yylval->literal = jv_parse_sized(yytext, yyleng); return LITERAL; } From 8fe9c8a22a0f43c8e34df5bc92df98c498c9a3f4 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 3 Sep 2012 15:33:59 +0100 Subject: [PATCH 030/284] Make assignment work again: = and |= operators. --- c/execute.c | 37 ++++++++++++++++++------------------- c/jv.h | 2 +- c/opcode_list.h | 1 - 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/c/execute.c b/c/execute.c index c22d1df3..0c31e072 100644 --- a/c/execute.c +++ b/c/execute.c @@ -24,14 +24,18 @@ int pathsize; // number of allocated elements // FIXME mem int path_push(stackval sv, jv val) { - return 0; int pos = sv.pathidx; assert(pos <= pathsize); assert(pos >= 0); if (pos == pathsize) { - pathsize = pathsize ? pathsize * 2 : 100; + int oldpathsize = pathsize; + pathsize = oldpathsize ? oldpathsize * 2 : 100; pathbuf = realloc(pathbuf, sizeof(pathbuf[0]) * pathsize); + for (int i=oldpathsize; i Date: Mon, 3 Sep 2012 16:14:52 +0100 Subject: [PATCH 031/284] Support "null" in JQ programs --- c/builtin.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/c/builtin.c b/c/builtin.c index d468e7b7..35e15471 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -10,6 +10,10 @@ static void f_true(jv input[], jv output[]) { output[0] = jv_true(); } +static void f_null(jv input[], jv output[]) { + jv_free(input[0]); + output[0] = jv_null(); +} static void f_plus(jv input[], jv output[]) { jv_free(input[0]); @@ -30,6 +34,7 @@ static void f_plus(jv input[], jv output[]) { struct cfunction function_list[] = { {f_true, "true", CALL_BUILTIN_1_1}, {f_false, "false", CALL_BUILTIN_1_1}, + {f_null, "null", CALL_BUILTIN_1_1}, {f_plus, "_plus", CALL_BUILTIN_3_1}, }; struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; From a8c3648ca5ebcb9c824f3df86a4c2fbe57c09d6d Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 3 Sep 2012 16:16:14 +0100 Subject: [PATCH 032/284] JV_KIND_INVALID values to represent failed lookups, etc + various tests. --- c/execute.c | 5 ++--- c/jv.c | 13 ++++++++++++- c/jv.h | 6 ++++++ c/main.c | 10 +++++----- c/testdata | 29 ++++++++++++++++++++++++----- 5 files changed, 49 insertions(+), 14 deletions(-) diff --git a/c/execute.c b/c/execute.c index 0c31e072..d98872b3 100644 --- a/c/execute.c +++ b/c/execute.c @@ -321,8 +321,7 @@ jv jq_next() { do_backtrack: case BACKTRACK: { if (!stack_restore()) { - // FIXME: invalid jv value - return jv_null(); + return jv_invalid(); } pc = *frame_current_retaddr(&frame_stk); frame_pop(&frame_stk); @@ -443,7 +442,7 @@ void run_program(struct bytecode* bc) { fgets(buf, sizeof(buf), stdin); jq_init(bc, jv_parse(buf)); jv result; - while (jv_get_kind(result = jq_next()) != JV_KIND_NULL) { + while (jv_is_valid(result = jq_next())) { jv_dump(result); printf("\n"); } diff --git a/c/jv.c b/c/jv.c index 198bfeda..4484dc9f 100644 --- a/c/jv.c +++ b/c/jv.c @@ -37,10 +37,15 @@ jv_kind jv_get_kind(jv x) { return x.kind; } +static const jv JV_INVALID = {JV_KIND_INVALID, {0}}; static const jv JV_NULL = {JV_KIND_NULL, {0}}; static const jv JV_FALSE = {JV_KIND_FALSE, {0}}; static const jv JV_TRUE = {JV_KIND_TRUE, {0}}; +jv jv_invalid() { + return JV_INVALID; +} + jv jv_true() { return JV_TRUE; } @@ -671,7 +676,13 @@ jv jv_object() { jv jv_object_get(jv object, jv key) { assert(jv_get_kind(object) == JV_KIND_OBJECT); assert(jv_get_kind(key) == JV_KIND_STRING); - jv val = jv_copy(*jvp_object_read(&object.val.complex, jvp_string_ptr(&key.val.complex))); + jv* slot = jvp_object_read(&object.val.complex, jvp_string_ptr(&key.val.complex)); + jv val; + if (slot) { + val = jv_copy(*slot); + } else { + val = jv_invalid(); + } jv_free(object); jv_free(key); return val; diff --git a/c/jv.h b/c/jv.h index 754f0316..b251329c 100644 --- a/c/jv.h +++ b/c/jv.h @@ -8,6 +8,7 @@ typedef enum { + JV_KIND_INVALID, JV_KIND_NULL, JV_KIND_FALSE, JV_KIND_TRUE, @@ -40,12 +41,14 @@ typedef struct { */ jv_kind jv_get_kind(jv); +static int jv_is_valid(jv x) { return jv_get_kind(x) != JV_KIND_INVALID; } jv jv_copy(jv); void jv_free(jv); int jv_equal(jv, jv); +jv jv_invalid(); jv jv_null(); jv jv_true(); jv jv_false(); @@ -95,6 +98,9 @@ static jv jv_lookup(jv t, jv k) { jv v; if (jv_get_kind(t) == JV_KIND_OBJECT && jv_get_kind(k) == JV_KIND_STRING) { v = jv_object_get(t, k); + if (!jv_is_valid(v)) { + v = jv_null(); + } } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_NUMBER) { // FIXME: don't do lookup for noninteger index v = jv_array_get(t, (int)jv_number_value(k)); diff --git a/c/main.c b/c/main.c index 5cdc7d62..5879d031 100644 --- a/c/main.c +++ b/c/main.c @@ -46,7 +46,7 @@ void run_tests() { if (skipline(buf)) break; jv expected = jv_parse(buf); jv actual = jq_next(); - if (!1) { + if (!jv_is_valid(actual)) { printf("Insufficient results\n"); pass = 0; break; @@ -59,14 +59,14 @@ void run_tests() { pass = 0; } } - if (pass && 0) { /* + if (pass) { jv extra = jq_next(); - if (extra) { + if (jv_is_valid(extra)) { printf("Superfluous result: "); - json_dumpf(extra, stdout, JSON_ENCODE_ANY); + jv_dump(extra); printf("\n"); pass = 0; - }*/ + } } jq_teardown(); bytecode_free(bc); diff --git a/c/testdata b/c/testdata index 2cdaaa5f..c6388d67 100644 --- a/c/testdata +++ b/c/testdata @@ -59,11 +59,9 @@ null {"foo": {"bar": 42}, "bar": "badvalue"} 42 - -# FIXME strings -# .["foo"].bar -# {"foo": {"bar": 42}, "bar": "badvalue"} -# 42 +.["foo"].bar +{"foo": {"bar": 42}, "bar": "badvalue"} +42 # @@ -172,6 +170,12 @@ true [1] true +null,1,null +"hello" +null +1 +null + [1,2,3] [5,6] [1,2,3] @@ -193,3 +197,18 @@ def id(x):x; 2000 as $x | def f(x):1 as $x | id([$x, x, x]); def g(x): 100 as $x [[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | g; f[0] | [f][0][1] | f] "woo, testing!" [[110.0, 130.0], [210.0, 130.0], [110.0, 230.0], [210.0, 230.0], [120.0, 160.0], [220.0, 160.0], [120.0, 260.0], [220.0, 260.0]] + +# +# Assignment +# +.message = "goodbye" +{"message": "hello"} +{"message": "goodbye"} + +.foo = .bar +{"bar":42} +{"foo":42, "bar":42} + +def inc(x): x |= .+1; inc(.[].a) +[{"a":1,"b":2},{"a":2,"b":4},{"a":7,"b":8}] +[{"a":2,"b":2},{"a":3,"b":4},{"a":8,"b":8}] From c9dbe1aff87fcee77843e168e0417fe708aaf4a8 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 3 Sep 2012 16:42:58 +0100 Subject: [PATCH 033/284] squash a debug printf --- c/jv_parse.c | 1 - 1 file changed, 1 deletion(-) diff --git a/c/jv_parse.c b/c/jv_parse.c index 1f6a20aa..ccff509d 100644 --- a/c/jv_parse.c +++ b/c/jv_parse.c @@ -347,7 +347,6 @@ static pfunc finish(struct jv_parser* p) { } jv jv_parse_sized(const char* string, int length) { - printf("'%s' [%d]", string, length); struct jv_parser parser; jv_parser_init(&parser); From eea05ff9248210210977cd5679b90437bc3733ff Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 3 Sep 2012 16:50:38 +0100 Subject: [PATCH 034/284] Perl-style autovivification. .foo.bar = 1 will cause objects to be created if they don't exist. --- c/jv.c | 19 ++++++++++++++----- c/jv.h | 32 +++++++++++++++++++++++++++----- c/testdata | 18 ++++++++++++++++-- 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/c/jv.c b/c/jv.c index 4484dc9f..9a3d308f 100644 --- a/c/jv.c +++ b/c/jv.c @@ -125,10 +125,13 @@ static int jvp_array_length(jv_complex* a) { } static jv* jvp_array_read(jv_complex* a, int i) { - assert(i >= 0 && i < jvp_array_length(a)); - jvp_array* array = jvp_array_ptr(a); - assert(i + a->i[0] < array->length); - return &array->elements[i + a->i[0]]; + if (i >= 0 && i < jvp_array_length(a)) { + jvp_array* array = jvp_array_ptr(a); + assert(i + a->i[0] < array->length); + return &array->elements[i + a->i[0]]; + } else { + return 0; + } } static jv* jvp_array_write(jv_complex* a, int i) { @@ -223,7 +226,13 @@ int jv_array_length(jv j) { jv jv_array_get(jv j, int idx) { assert(jv_get_kind(j) == JV_KIND_ARRAY); - jv val = jv_copy(*jvp_array_read(&j.val.complex, idx)); + jv* slot = jvp_array_read(&j.val.complex, idx); + jv val; + if (slot) { + val = jv_copy(*slot); + } else { + val = jv_invalid(); + } jv_free(j); return val; } diff --git a/c/jv.h b/c/jv.h index b251329c..8d9ebadb 100644 --- a/c/jv.h +++ b/c/jv.h @@ -104,6 +104,14 @@ static jv jv_lookup(jv t, jv k) { } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_NUMBER) { // FIXME: don't do lookup for noninteger index v = jv_array_get(t, (int)jv_number_value(k)); + if (!jv_is_valid(v)) { + v = jv_null(); + } + } else if (jv_get_kind(t) == JV_KIND_NULL && + (jv_get_kind(k) == JV_KIND_STRING || jv_get_kind(k) == JV_KIND_NUMBER)) { + jv_free(t); + jv_free(k); + v = jv_null(); } else { assert(0&&"bad lookup"); } @@ -118,12 +126,26 @@ static jv jv_lookup(jv t, jv k) { } static jv jv_modify(jv t, jv k, jv v) { - if (jv_get_kind(t) == JV_KIND_OBJECT && jv_get_kind(k) == JV_KIND_STRING) { - t = jv_object_set(t, k, v); - } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_NUMBER) { - t = jv_array_set(t, (int)jv_number_value(k), v); + if (jv_get_kind(k) == JV_KIND_STRING) { + if (jv_get_kind(t) == JV_KIND_NULL) { + t = jv_object(); + } + if (jv_get_kind(t) == JV_KIND_OBJECT) { + t = jv_object_set(t, k, v); + } else { + assert(0 && "bad mod - not an object"); + } + } else if (jv_get_kind(k) == JV_KIND_NUMBER) { + if (jv_get_kind(t) == JV_KIND_NULL) { + t = jv_array(); + } + if (jv_get_kind(t) == JV_KIND_ARRAY) { + t = jv_array_set(t, (int)jv_number_value(k), v); + } else { + assert(0 && "bad mod - not an array"); + } } else { - assert(0 && "bad mod"); + assert(0 && "bad mod - seriously, wtf"); } return t; } diff --git a/c/testdata b/c/testdata index c6388d67..70071186 100644 --- a/c/testdata +++ b/c/testdata @@ -133,12 +133,18 @@ null # Builtin functions # -# FIXME: floats vs. integer - 1+1 null 2 +1+1 +"wtasdf" +2.0 + +1e+0+0.001e3 +"I wonder what this will be?" +20e-1 + .+4 15 19.0 @@ -212,3 +218,11 @@ def id(x):x; 2000 as $x | def f(x):1 as $x | id([$x, x, x]); def g(x): 100 as $x def inc(x): x |= .+1; inc(.[].a) [{"a":1,"b":2},{"a":2,"b":4},{"a":7,"b":8}] [{"a":2,"b":2},{"a":3,"b":4},{"a":8,"b":8}] + +.[2][3] = 1 +[4] +[4, null, [null, null, null, 1]] + +.foo[2].bar = 1 +{"foo":[11], "bar":42} +{"foo":[11,null,{"bar":1}], "bar":42} From 32e324a283cea97a2c4c2016d10666ce83336dc7 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 3 Sep 2012 17:18:10 +0100 Subject: [PATCH 035/284] Fix a memory leak in JV and add more tests --- c/jv.c | 4 +++- c/testdata | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/c/jv.c b/c/jv.c index 9a3d308f..80b9b9b8 100644 --- a/c/jv.c +++ b/c/jv.c @@ -240,7 +240,9 @@ jv jv_array_get(jv j, int idx) { jv jv_array_set(jv j, int idx, jv val) { assert(jv_get_kind(j) == JV_KIND_ARRAY); // copy/free of val,j coalesced - *jvp_array_write(&j.val.complex, idx) = val; + jv* slot = jvp_array_write(&j.val.complex, idx); + jv_free(*slot); + *slot = val; return j; } diff --git a/c/testdata b/c/testdata index 70071186..6ddf09fd 100644 --- a/c/testdata +++ b/c/testdata @@ -215,6 +215,14 @@ def id(x):x; 2000 as $x | def f(x):1 as $x | id([$x, x, x]); def g(x): 100 as $x {"bar":42} {"foo":42, "bar":42} +.foo |= .+1 +{"foo": 42} +{"foo": 43} + +.[0].a |= {"old":., "new":(.+1)} +[{"a":1,"b":2}] +[{"a":{"old":1, "new":2},"b":2}] + def inc(x): x |= .+1; inc(.[].a) [{"a":1,"b":2},{"a":2,"b":4},{"a":7,"b":8}] [{"a":2,"b":2},{"a":3,"b":4},{"a":8,"b":8}] From 520c7bb15ea01e9516ff1387ec8b01a5b5b7c1c5 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 3 Sep 2012 17:26:52 +0100 Subject: [PATCH 036/284] Fix some confusion between "null" and "invalid". --- c/execute.c | 5 ++--- c/frame_layout.h | 2 +- c/jv.c | 4 ++-- c/jv_parse.c | 6 +++--- c/main.c | 2 ++ 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/c/execute.c b/c/execute.c index d98872b3..b7818d12 100644 --- a/c/execute.c +++ b/c/execute.c @@ -22,7 +22,6 @@ typedef struct { jv* pathbuf; int pathsize; // number of allocated elements -// FIXME mem int path_push(stackval sv, jv val) { int pos = sv.pathidx; assert(pos <= pathsize); @@ -32,7 +31,7 @@ int path_push(stackval sv, jv val) { pathsize = oldpathsize ? oldpathsize * 2 : 100; pathbuf = realloc(pathbuf, sizeof(pathbuf[0]) * pathsize); for (int i=oldpathsize; iconstants), *pc++); - //FIXME assert(v); + assert(jv_is_valid(v)); stack_push(stackval_replace(stack_pop(), v)); break; } diff --git a/c/frame_layout.h b/c/frame_layout.h index d2218e92..f098272e 100644 --- a/c/frame_layout.h +++ b/c/frame_layout.h @@ -88,7 +88,7 @@ static frame_ptr frame_push(struct forkable_stack* stk, struct closure cl, uint1 cc->retaddr = retaddr; cc->is_backtrack_frame = 0; for (int i=0; inlocals; i++) { - *frame_local_var(fp, i) = jv_null(); + *frame_local_var(fp, i) = jv_invalid(); } return fp; } diff --git a/c/jv.c b/c/jv.c index 80b9b9b8..c4a5af1c 100644 --- a/c/jv.c +++ b/c/jv.c @@ -619,7 +619,7 @@ static jv* jvp_object_write(jv_complex* object, jvp_string* key) { jvp_string_free_p(key); } else { slot = jvp_object_add_slot(object, key, bucket); - slot->value = jv_null(); + slot->value = jv_invalid(); } if (slot == 0) { jvp_object_rehash(object); @@ -627,7 +627,7 @@ static jv* jvp_object_write(jv_complex* object, jvp_string* key) { assert(!jvp_object_find_slot(object, key, bucket)); slot = jvp_object_add_slot(object, key, bucket); assert(slot); - slot->value = jv_null(); + slot->value = jv_invalid(); } return &slot->value; } diff --git a/c/jv_parse.c b/c/jv_parse.c index ccff509d..987bb9e2 100644 --- a/c/jv_parse.c +++ b/c/jv_parse.c @@ -18,7 +18,7 @@ void jv_parser_init(struct jv_parser* p) { p->stack = 0; p->stacklen = p->stackpos = 0; p->hasnext = 0; - p->next = jv_null(); //FIXME: jv_invalid + p->next = jv_invalid(); //FIXME: jv_invalid p->tokenbuf = 0; p->tokenlen = p->tokenpos = 0; p->st = JV_PARSER_NORMAL; @@ -357,13 +357,13 @@ jv jv_parse_sized(const char* string, int length) { presult msg = scan(&parser, ch); if (msg){ printf("ERROR: %s (parsing '%s')\n", msg, string); - return jv_null(); + return jv_invalid(); } } presult msg = finish(&parser); if (msg) { printf("ERROR: %s (parsing '%s')\n", msg, string); - return jv_null(); + return jv_invalid(); } jv value = jv_copy(parser.next); jv_parser_free(&parser); diff --git a/c/main.c b/c/main.c index 5879d031..bad85418 100644 --- a/c/main.c +++ b/c/main.c @@ -40,11 +40,13 @@ void run_tests() { printf("\n"); fgets(buf, sizeof(buf), testdata); jv input = jv_parse(buf); + assert(jv_is_valid(input)); jq_init(bc, input); while (fgets(buf, sizeof(buf), testdata)) { if (skipline(buf)) break; jv expected = jv_parse(buf); + assert(jv_is_valid(expected)); jv actual = jq_next(); if (!jv_is_valid(actual)) { printf("Insufficient results\n"); From 5add2c2ceb763104206cd70bd2678575362c1008 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 4 Sep 2012 15:34:34 +0100 Subject: [PATCH 037/284] if-then-else and defined-or operators --- c/compile.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- c/compile.h | 4 +++- c/execute.c | 13 +++++++++++++ c/lexer.l | 5 +++++ c/opcode_list.h | 1 + c/parser.y | 15 +++++++++++++++ c/testdata | 15 +++++++++++++++ 7 files changed, 97 insertions(+), 3 deletions(-) diff --git a/c/compile.c b/c/compile.c index b7fcc4f2..c83a5583 100644 --- a/c/compile.c +++ b/c/compile.c @@ -312,8 +312,51 @@ block gen_assign(block expr) { return c; } -block gen_else(block a, block b) { - assert(0); +block gen_definedor(block a, block b) { + // var found := false + block c = gen_op_simple(DUP); + block_append(&c, gen_op_const(LOADK, jv_false())); + block found_var = block_bind(gen_op_var_unbound(STOREV, "found"), + gen_noop(), OP_HAS_VARIABLE); + block_append(&c, found_var); + + // if found, backtrack. Otherwise execute b + block tail = gen_op_simple(DUP); + block_append(&tail, gen_op_var_bound(LOADV, found_var)); + block backtrack = gen_op_simple(BACKTRACK); + block_append(&tail, gen_op_target(JUMP_F, backtrack)); + block_append(&tail, backtrack); + block_append(&tail, gen_op_simple(POP)); + block_append(&tail, b); + + // try again + block if_notfound = gen_op_simple(BACKTRACK); + + // found := true, produce result + block if_found = gen_op_simple(DUP); + block_append(&if_found, gen_op_const(LOADK, jv_true())); + block_append(&if_found, gen_op_var_bound(STOREV, found_var)); + block_append(&if_found, gen_op_target(JUMP, tail)); + + block_append(&c, gen_op_target(FORK, if_notfound)); + block_append(&c, a); + block_append(&c, gen_op_target(JUMP_F, if_found)); + block_append(&c, if_found); + block_append(&c, if_notfound); + block_append(&c, tail); + + return c; +} + +block gen_cond(block cond, block iftrue, block iffalse) { + block b = gen_op_simple(DUP); + block_append(&b, cond); + + block_append(&iftrue, gen_op_target(JUMP, iffalse)); + block_append(&b, gen_op_target(JUMP_F, iftrue)); + block_append(&b, block_join(gen_op_simple(POP), iftrue)); + block_append(&b, block_join(gen_op_simple(POP), iffalse)); + return b; } block gen_cbinding(struct symbol_table* t, block code) { diff --git a/c/compile.h b/c/compile.h index 5f0be89b..5a2faf7b 100644 --- a/c/compile.h +++ b/c/compile.h @@ -26,7 +26,9 @@ block gen_subexp(block a); block gen_both(block a, block b); block gen_collect(block expr); block gen_assign(block expr); -block gen_else(block a, block b); +block gen_definedor(block a, block b); + +block gen_cond(block cond, block iftrue, block iffalse); block gen_cbinding(struct symbol_table* functions, block b); diff --git a/c/execute.c b/c/execute.c index b7818d12..5e6a2c51 100644 --- a/c/execute.c +++ b/c/execute.c @@ -59,6 +59,7 @@ typedef struct { } data_stk_elem; void stack_push(stackval val) { + assert(jv_is_valid(val.value)); data_stk_elem* s = forkable_stack_push(&data_stk, sizeof(data_stk_elem)); s->sv = val; } @@ -70,6 +71,7 @@ stackval stack_pop() { sv.value = jv_copy(sv.value); } forkable_stack_pop(&data_stk); + assert(jv_is_valid(sv.value)); return sv; } @@ -292,6 +294,17 @@ jv jq_next() { break; } + case JUMP_F: { + uint16_t offset = *pc++; + stackval t = stack_pop(); + jv_kind kind = jv_get_kind(t.value); + if (kind == JV_KIND_FALSE || kind == JV_KIND_NULL) { + pc += offset; + } + stack_push(t); // FIXME do this better + break; + } + case EACH: stack_push(stackval_root(jv_number(0))); // fallthrough diff --git a/c/lexer.l b/c/lexer.l index 4acb026a..e3c140b6 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -13,6 +13,11 @@ "as" { return AS; } "def" { return DEF; } "|=" { return SETPIPE; } +"if" { return IF; } +"then" { return THEN; } +"else" { return ELSE; } +"end" { return END; } +"//" { return DEFINEDOR; } "."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];} \"(\\.|[^\\"])*\" | diff --git a/c/opcode_list.h b/c/opcode_list.h index 7f2c144a..30e7203d 100644 --- a/c/opcode_list.h +++ b/c/opcode_list.h @@ -10,6 +10,7 @@ OP(YIELD, NONE, 1, 0) OP(EACH, NONE, 1, 1) OP(FORK, BRANCH, 0, 0) OP(JUMP, BRANCH, 0, 0) +OP(JUMP_F,BRANCH, 1, 0) OP(BACKTRACK, NONE, 0, 0) OP(APPEND, NONE, 2, 1) OP(INSERT, NONE, 4, 2) diff --git a/c/parser.y b/c/parser.y index 36292453..d4e8d8f4 100644 --- a/c/parser.y +++ b/c/parser.y @@ -25,13 +25,20 @@ %left '|' %left ',' %token EQ "==" +%token DEFINEDOR "//" %token AS "as" %token DEF "def" %token SETPIPE "|=" +%token IF "if" +%token THEN "then" +%token ELSE "else" +%token END "end" +%right "//" %nonassoc '=' SETPIPE %nonassoc EQ %left '+' + %type Exp Term MkDict MkDictPair ExpD %{ @@ -78,6 +85,10 @@ Term "as" '$' IDENT '|' Exp { jv_free($4); } | +"if" Exp "then" Exp "else" Exp "end" { + $$ = gen_cond($2, $4, $6); +} | + Exp '=' Exp { block assign = gen_op_simple(DUP); block_append(&assign, $3); @@ -87,6 +98,10 @@ Exp '=' Exp { $$ = gen_assign(assign); } | +Exp "//" Exp { + $$ = gen_definedor($1, $3); +} | + Exp "|=" Exp { block assign = $1; block_append(&assign, gen_op_simple(DUP)); diff --git a/c/testdata b/c/testdata index 6ddf09fd..888d8b74 100644 --- a/c/testdata +++ b/c/testdata @@ -234,3 +234,18 @@ def inc(x): x |= .+1; inc(.[].a) .foo[2].bar = 1 {"foo":[11], "bar":42} {"foo":[11,null,{"bar":1}], "bar":42} + +# +# Conditionals +# + +[.[] | if .foo then "yep" else "nope" end] +[{"foo":0},{"foo":1},{"foo":[]},{"foo":true},{"foo":false},{"foo":null},{"foo":"foo"},{}] +["yep","yep","yep","yep","nope","nope","yep","nope"] + +# FIXME: define/test behaviour of 'if (.foo,.bar) then A else B end' + +[.[] | [.foo[] // .bar]] +[{"foo":[1,2], "bar": 42}, {"foo":[1], "bar": null}, {"foo":[null,false,3], "bar": 18}, {"foo":[], "bar":42}, {"foo": [null,false,null], "bar": 41}] +[[1,2], [1], [3], [42], [41]] + From 328c4a13f1d63b02cbc7afe8e46a16ef4f896f07 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 4 Sep 2012 16:05:24 +0100 Subject: [PATCH 038/284] Add "elif" to if-then-else constructs. --- c/lexer.l | 1 + c/parser.y | 15 ++++++++++++--- c/testdata | 5 +++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/c/lexer.l b/c/lexer.l index e3c140b6..98365f1f 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -16,6 +16,7 @@ "if" { return IF; } "then" { return THEN; } "else" { return ELSE; } +"elif" { return ELSE_IF; } "end" { return END; } "//" { return DEFINEDOR; } "."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];} diff --git a/c/parser.y b/c/parser.y index d4e8d8f4..165cdb42 100644 --- a/c/parser.y +++ b/c/parser.y @@ -32,6 +32,7 @@ %token IF "if" %token THEN "then" %token ELSE "else" +%token ELSE_IF "elif" %token END "end" %right "//" %nonassoc '=' SETPIPE @@ -39,7 +40,7 @@ %left '+' -%type Exp Term MkDict MkDictPair ExpD +%type Exp Term MkDict MkDictPair ExpD ElseBody %{ #include "lexer.yy.h" @@ -85,8 +86,8 @@ Term "as" '$' IDENT '|' Exp { jv_free($4); } | -"if" Exp "then" Exp "else" Exp "end" { - $$ = gen_cond($2, $4, $6); +"if" Exp "then" Exp ElseBody { + $$ = gen_cond($2, $4, $5); } | Exp '=' Exp { @@ -128,6 +129,14 @@ Term { $$ = $1; } +ElseBody: +"elif" Exp "then" Exp ElseBody { + $$ = gen_cond($2, $4, $5); +} | +"else" Exp "end" { + $$ = $2; +} + ExpD: ExpD '|' ExpD { diff --git a/c/testdata b/c/testdata index 888d8b74..3fe231f5 100644 --- a/c/testdata +++ b/c/testdata @@ -243,6 +243,11 @@ def inc(x): x |= .+1; inc(.[].a) [{"foo":0},{"foo":1},{"foo":[]},{"foo":true},{"foo":false},{"foo":null},{"foo":"foo"},{}] ["yep","yep","yep","yep","nope","nope","yep","nope"] +[.[] | if .baz then "strange" elif .foo then "yep" else "nope" end] +[{"foo":0},{"foo":1},{"foo":[]},{"foo":true},{"foo":false},{"foo":null},{"foo":"foo"},{}] +["yep","yep","yep","yep","nope","nope","yep","nope"] + + # FIXME: define/test behaviour of 'if (.foo,.bar) then A else B end' [.[] | [.foo[] // .bar]] From c5ab3b2336a3ad14844bd91beae5b4dbca2c2926 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 4 Sep 2012 20:34:43 +0100 Subject: [PATCH 039/284] Move some unicode handling stuff to a separate file. --- c/Makefile | 2 +- c/jv_parse.c | 24 ++---------------------- c/jv_unicode.c | 30 ++++++++++++++++++++++++++++++ c/jv_unicode.h | 7 +++++++ 4 files changed, 40 insertions(+), 23 deletions(-) create mode 100644 c/jv_unicode.c create mode 100644 c/jv_unicode.h diff --git a/c/Makefile b/c/Makefile index d437b143..6496da8b 100644 --- a/c/Makefile +++ b/c/Makefile @@ -17,7 +17,7 @@ parser.tab.c: parser.y lexer.yy.h bison -W -d parser.y -v --report-file=parser.info parser.tab.h: parser.tab.c -parsertest: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c +parsertest: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c $(CC) -o $@ $^ jv_test: jv_test.c jv.c jv_print.c jv_dtoa.c diff --git a/c/jv_parse.c b/c/jv_parse.c index 987bb9e2..7a8c811e 100644 --- a/c/jv_parse.c +++ b/c/jv_parse.c @@ -4,6 +4,7 @@ #include "jv.h" #include "jv_dtoa.h" #include "jv_parse.h" +#include "jv_unicode.h" typedef const char* presult; @@ -157,27 +158,6 @@ static int unhex4(char* hex) { return r; } -static int utf8_encode(int codepoint, char* out) { - assert(codepoint >= 0 && codepoint <= 0x10FFFF); - char* start = out; - if (codepoint <= 0x7F) { - *out++ = codepoint; - } else if (codepoint <= 0x7FF) { - *out++ = 0xC0 + ((codepoint & 0x7C0) >> 6); - *out++ = 0x80 + ((codepoint & 0x03F)); - } else if(codepoint <= 0xFFFF) { - *out++ = 0xE0 + ((codepoint & 0xF000) >> 12); - *out++ = 0x80 + ((codepoint & 0x0FC0) >> 6); - *out++ = 0x80 + ((codepoint & 0x003F)); - } else { - *out++ = 0xF0 + ((codepoint & 0x1C0000) >> 18); - *out++ = 0x80 + ((codepoint & 0x03F000) >> 12); - *out++ = 0x80 + ((codepoint & 0x000FC0) >> 6); - *out++ = 0x80 + ((codepoint & 0x00003F)); - } - return out - start; -} - static pfunc found_string(struct jv_parser* p) { char* in = p->tokenbuf; char* out = p->tokenbuf; @@ -217,7 +197,7 @@ static pfunc found_string(struct jv_parser* p) { |(surrogate - 0xDC00)); } // FIXME assert valid codepoint - out += utf8_encode(codepoint, out); + out += jvp_utf8_encode(codepoint, out); break; default: diff --git a/c/jv_unicode.c b/c/jv_unicode.c new file mode 100644 index 00000000..b1475ff6 --- /dev/null +++ b/c/jv_unicode.c @@ -0,0 +1,30 @@ +#include +#include "jv_unicode.h" +int jvp_utf8_encode_length(int codepoint) { + if (codepoint <= 0x7F) return 1; + else if (codepoint <= 0x7FF) return 2; + else if (codepoint <= 0xFFFF) return 3; + else return 4; +} + +int jvp_utf8_encode(int codepoint, char* out) { + assert(codepoint >= 0 && codepoint <= 0x10FFFF); + char* start = out; + if (codepoint <= 0x7F) { + *out++ = codepoint; + } else if (codepoint <= 0x7FF) { + *out++ = 0xC0 + ((codepoint & 0x7C0) >> 6); + *out++ = 0x80 + ((codepoint & 0x03F)); + } else if(codepoint <= 0xFFFF) { + *out++ = 0xE0 + ((codepoint & 0xF000) >> 12); + *out++ = 0x80 + ((codepoint & 0x0FC0) >> 6); + *out++ = 0x80 + ((codepoint & 0x003F)); + } else { + *out++ = 0xF0 + ((codepoint & 0x1C0000) >> 18); + *out++ = 0x80 + ((codepoint & 0x03F000) >> 12); + *out++ = 0x80 + ((codepoint & 0x000FC0) >> 6); + *out++ = 0x80 + ((codepoint & 0x00003F)); + } + assert(out - start == jvp_utf8_encode_length(codepoint)); + return out - start; +} diff --git a/c/jv_unicode.h b/c/jv_unicode.h new file mode 100644 index 00000000..041c29aa --- /dev/null +++ b/c/jv_unicode.h @@ -0,0 +1,7 @@ +#ifndef JV_UNICODE_H +#define JV_UNICODE_H +int jvp_utf8_decode_length(char startchar); + +int jvp_utf8_encode_length(int codepoint); +int jvp_utf8_encode(int codepoint, char* out); +#endif From 6e6ea507630eceafd2cb2eb8e25bae231ee6f8a6 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 4 Sep 2012 20:38:59 +0100 Subject: [PATCH 040/284] Short-circuiting Boolean "and" and "or" operators. --- c/compile.c | 45 ++++++++++++++++++++++++++++++++++++++++----- c/compile.h | 2 ++ c/lexer.l | 2 ++ c/parser.y | 12 ++++++++++++ c/testdata | 6 ++++++ 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/c/compile.c b/c/compile.c index c83a5583..c4782f1d 100644 --- a/c/compile.c +++ b/c/compile.c @@ -348,14 +348,49 @@ block gen_definedor(block a, block b) { return c; } +static block gen_condbranch(block iftrue, block iffalse) { + block b = gen_noop(); + block_append(&iftrue, gen_op_target(JUMP, iffalse)); + block_append(&b, gen_op_target(JUMP_F, iftrue)); + block_append(&b, iftrue); + block_append(&b, iffalse); + return b; +} + +block gen_and(block a, block b) { + // a and b = if a then (if b then true else false) else false + block code = gen_op_simple(DUP); + block_append(&code, a); + + block if_a_true = gen_op_simple(POP); + block_append(&if_a_true, b); + block_append(&if_a_true, gen_condbranch(gen_op_const(LOADK, jv_true()), + gen_op_const(LOADK, jv_false()))); + block_append(&code, gen_condbranch(if_a_true, + block_join(gen_op_simple(POP), gen_op_const(LOADK, jv_false())))); + return code; +} + +block gen_or(block a, block b) { + // a or b = if a then true else (if b then true else false) + block code = gen_op_simple(DUP); + block_append(&code, a); + + block if_a_false = gen_op_simple(POP); + block_append(&if_a_false, b); + block_append(&if_a_false, gen_condbranch(gen_op_const(LOADK, jv_true()), + gen_op_const(LOADK, jv_false()))); + block_append(&code, gen_condbranch(block_join(gen_op_simple(POP), gen_op_const(LOADK, jv_true())), + if_a_false)); + return code; + +} + block gen_cond(block cond, block iftrue, block iffalse) { block b = gen_op_simple(DUP); block_append(&b, cond); - - block_append(&iftrue, gen_op_target(JUMP, iffalse)); - block_append(&b, gen_op_target(JUMP_F, iftrue)); - block_append(&b, block_join(gen_op_simple(POP), iftrue)); - block_append(&b, block_join(gen_op_simple(POP), iffalse)); + block_append(&b, gen_condbranch(block_join(gen_op_simple(POP), iftrue), + block_join(gen_op_simple(POP), iffalse))); return b; } diff --git a/c/compile.h b/c/compile.h index 5a2faf7b..1a7c62c6 100644 --- a/c/compile.h +++ b/c/compile.h @@ -27,6 +27,8 @@ block gen_both(block a, block b); block gen_collect(block expr); block gen_assign(block expr); block gen_definedor(block a, block b); +block gen_and(block a, block b); +block gen_or(block a, block b); block gen_cond(block cond, block iftrue, block iffalse); diff --git a/c/lexer.l b/c/lexer.l index 98365f1f..47789d29 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -17,6 +17,8 @@ "then" { return THEN; } "else" { return ELSE; } "elif" { return ELSE_IF; } +"and" { return AND; } +"or" { return OR; } "end" { return END; } "//" { return DEFINEDOR; } "."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];} diff --git a/c/parser.y b/c/parser.y index 165cdb42..5b997e62 100644 --- a/c/parser.y +++ b/c/parser.y @@ -34,9 +34,13 @@ %token ELSE "else" %token ELSE_IF "elif" %token END "end" +%token AND "and" +%token OR "or" %right "//" %nonassoc '=' SETPIPE %nonassoc EQ +%left OR +%left AND %left '+' @@ -99,6 +103,14 @@ Exp '=' Exp { $$ = gen_assign(assign); } | +Exp "or" Exp { + $$ = gen_or($1, $3); +} | + +Exp "and" Exp { + $$ = gen_and($1, $3); +} | + Exp "//" Exp { $$ = gen_definedor($1, $3); } | diff --git a/c/testdata b/c/testdata index 3fe231f5..4241c6cd 100644 --- a/c/testdata +++ b/c/testdata @@ -254,3 +254,9 @@ def inc(x): x |= .+1; inc(.[].a) [{"foo":[1,2], "bar": 42}, {"foo":[1], "bar": null}, {"foo":[null,false,3], "bar": 18}, {"foo":[], "bar":42}, {"foo": [null,false,null], "bar": 41}] [[1,2], [1], [3], [42], [41]] +.[] | [.[0] and .[1], .[0] or .[1]] +[[true,[]], [false,1], [42,null], [null,false]] +[true,true] +[false,true] +[false,true] +[false,false] From da5d653de8920091fb689a85eabdfc2c34278b1b Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 4 Sep 2012 20:43:40 +0100 Subject: [PATCH 041/284] Add a Boolean "not" operator. Not wholly convinced this is a good idea, maybe "not" should be a builtin function instead? 'not (.a == .b)' vs. '.a == .b | not' --- c/compile.c | 6 +++++- c/compile.h | 1 + c/lexer.l | 1 + c/parser.y | 5 +++++ c/testdata | 4 ++++ 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/c/compile.c b/c/compile.c index c4782f1d..b7f91aa3 100644 --- a/c/compile.c +++ b/c/compile.c @@ -383,7 +383,11 @@ block gen_or(block a, block b) { block_append(&code, gen_condbranch(block_join(gen_op_simple(POP), gen_op_const(LOADK, jv_true())), if_a_false)); return code; - +} + +block gen_not(block a) { + return block_join(a, gen_condbranch(gen_op_const(LOADK, jv_false()), + gen_op_const(LOADK, jv_true()))); } block gen_cond(block cond, block iftrue, block iffalse) { diff --git a/c/compile.h b/c/compile.h index 1a7c62c6..8f9526b0 100644 --- a/c/compile.h +++ b/c/compile.h @@ -29,6 +29,7 @@ block gen_assign(block expr); block gen_definedor(block a, block b); block gen_and(block a, block b); block gen_or(block a, block b); +block gen_not(block a); block gen_cond(block cond, block iftrue, block iffalse); diff --git a/c/lexer.l b/c/lexer.l index 47789d29..f2651762 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -19,6 +19,7 @@ "elif" { return ELSE_IF; } "and" { return AND; } "or" { return OR; } +"not" { return NOT; } "end" { return END; } "//" { return DEFINEDOR; } "."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"\$" { return yytext[0];} diff --git a/c/parser.y b/c/parser.y index 5b997e62..54456d09 100644 --- a/c/parser.y +++ b/c/parser.y @@ -36,6 +36,7 @@ %token END "end" %token AND "and" %token OR "or" +%token NOT "not" %right "//" %nonassoc '=' SETPIPE %nonassoc EQ @@ -111,6 +112,10 @@ Exp "and" Exp { $$ = gen_and($1, $3); } | +"not" Exp { + $$ = gen_not($2); +} | + Exp "//" Exp { $$ = gen_definedor($1, $3); } | diff --git a/c/testdata b/c/testdata index 4241c6cd..f453edd3 100644 --- a/c/testdata +++ b/c/testdata @@ -260,3 +260,7 @@ def inc(x): x |= .+1; inc(.[].a) [false,true] [false,true] [false,false] + +[.[] | not .] +[1,0,false,null,true,"hello"] +[false,false,true,true,false,false] From 58a9b0cfe135f6a7a274c1717702c10ac0e7ee5b Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 4 Sep 2012 20:56:44 +0100 Subject: [PATCH 042/284] Make the test harness not segfault when a test fails (!) --- c/main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/c/main.c b/c/main.c index bad85418..b71bcad5 100644 --- a/c/main.c +++ b/c/main.c @@ -52,14 +52,16 @@ void run_tests() { printf("Insufficient results\n"); pass = 0; break; - } else if (!jv_equal(expected, actual)) { + } else if (!jv_equal(jv_copy(expected), jv_copy(actual))) { printf("Expected "); - jv_dump(expected); + jv_dump(jv_copy(expected)); printf(", but got "); - jv_dump(actual); + jv_dump(jv_copy(actual)); printf("\n"); pass = 0; } + jv_free(expected); + jv_free(actual); } if (pass) { jv extra = jq_next(); From 0fd7d4b30cafbc9a1e4fecfafe21921e2923daaa Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Thu, 6 Sep 2012 21:36:11 +0100 Subject: [PATCH 043/284] UTF8 coding utilities and unicode escaping in jv_dump()'d strings. Beyond the Basic Multilingual Plane, dead Cthulhu waits dreaming. --- c/Makefile | 4 ++++ c/gen_utf8_tables.py | 30 ++++++++++++++++++++++++++++++ c/jv_print.c | 30 ++++++++++++++++++++++++------ c/jv_unicode.c | 34 ++++++++++++++++++++++++++++++++++ c/jv_unicode.h | 4 ++++ 5 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 c/gen_utf8_tables.py diff --git a/c/Makefile b/c/Makefile index 6496da8b..2c4379de 100644 --- a/c/Makefile +++ b/c/Makefile @@ -8,6 +8,8 @@ clean: sed 's/.*`\(.*\)'\''.*/\1/' | grep -v '^all$$' | \ xargs rm +jv_utf8_tables.h: gen_utf8_tables.py + python $^ > $@ lexer.yy.c: lexer.l flex -o lexer.yy.c --header-file=lexer.yy.h lexer.l @@ -17,6 +19,8 @@ parser.tab.c: parser.y lexer.yy.h bison -W -d parser.y -v --report-file=parser.info parser.tab.h: parser.tab.c +jv_unicode.c: jv_utf8_tables.h + parsertest: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c $(CC) -o $@ $^ diff --git a/c/gen_utf8_tables.py b/c/gen_utf8_tables.py new file mode 100644 index 00000000..9d8dc3c0 --- /dev/null +++ b/c/gen_utf8_tables.py @@ -0,0 +1,30 @@ +#!/usr/bin/python + +mask = lambda n: (1 << n) - 1 + + +def print_table(type, name, t): + assert len(t) == 256 + print "const static",type, name+"[]", "=" + first = True + for i in range(0,len(t),16): + print (" {" if i == 0 else " ") +\ + ", ".join("0x%02x"%n for n in t[i:i+16]) + \ + ("," if i + 16 < 256 else "};") + + +def utf8info(c): + if c < 0x80: return 1, mask(7) + if 0x80 <= c <= 0xBF: return 255, mask(6) + if 0xC0 <= c <= 0xC1: return 0, 0 + if 0xC2 <= c <= 0xDF: return 2, mask(5) + if 0xE0 <= c <= 0xEF: return 3, mask(4) + if 0xF0 <= c <= 0xF4: return 4, mask(3) + if 0xF4 <= c <= 0xFF: return 0, 0 + +table = lambda i: [utf8info(c)[i] for c in range(256)] + +print "#define UTF8_CONTINUATION_BYTE ((unsigned char)255)" + +print_table("unsigned char", "utf8_coding_length", table(0)) +print_table("unsigned char", "utf8_coding_bits", table(1)) diff --git a/c/jv_print.c b/c/jv_print.c index c082e935..c9808ea7 100644 --- a/c/jv_print.c +++ b/c/jv_print.c @@ -1,22 +1,25 @@ #include "jv.h" #include +#include +#include #include "jv_dtoa.h" +#include "jv_unicode.h" static void jv_dump_string(jv str, int ascii_only) { assert(jv_get_kind(str) == JV_KIND_STRING); const char* i = jv_string_value(str); - const char* end = i + jv_string_length(str); - while (i < end) { - int unicode_escape; - int c = (unsigned char)*i++; + const char* end = i + jv_string_length(jv_copy(str)); + int c; + while ((i = jvp_utf8_next(i, end, &c))) { + assert(c != -1); + int unicode_escape = 0; if (0x20 <= c && c <= 0x7E) { // printable ASCII if (c == '"' || c == '\\') { putchar('\\'); } putchar(c); - unicode_escape = 0; } else if (c < 0x20 || c == 0x7F) { // ASCII control character switch (c) { @@ -44,8 +47,21 @@ static void jv_dump_string(jv str, int ascii_only) { unicode_escape = 1; break; } + } else { + unicode_escape = 1; + } + if (unicode_escape) { + if (c <= 0xffff) { + printf("\\u%04x", c); + } else { + c -= 0x10000; + printf("\\u%04x\\u%04x", + 0xD800 | ((c & 0xffc00) >> 10), + 0xDC00 | (c & 0x003ff)); + } } } + assert(c != -1); } static void jv_dump_term(struct dtoa_context* C, jv x) { @@ -65,7 +81,9 @@ static void jv_dump_term(struct dtoa_context* C, jv x) { break; case JV_KIND_STRING: // FIXME: all sorts of broken - printf("\"%s\"", jv_string_value(x)); + putchar('"'); + jv_dump_string(x, 0); + putchar('"'); break; case JV_KIND_ARRAY: { printf("["); diff --git a/c/jv_unicode.c b/c/jv_unicode.c index b1475ff6..375ad367 100644 --- a/c/jv_unicode.c +++ b/c/jv_unicode.c @@ -1,5 +1,39 @@ +#include #include #include "jv_unicode.h" +#include "jv_utf8_tables.h" + +const char* jvp_utf8_next(const char* in, const char* end, int* codepoint) { + if (in == end) { + codepoint = 0; + return 0; + } + unsigned char first = (unsigned char)in[0]; + int length = utf8_coding_length[first]; + if (length == 0 || length == UTF8_CONTINUATION_BYTE || in + length > end) { + *codepoint = -1; + return 0; + } + *codepoint = ((unsigned)in[0]) & utf8_coding_bits[first]; + for (int i=1; i Date: Thu, 6 Sep 2012 21:44:46 +0100 Subject: [PATCH 044/284] null and string literals now exist, so add tests --- c/testdata | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/c/testdata b/c/testdata index f453edd3..5aa3efed 100644 --- a/c/testdata +++ b/c/testdata @@ -13,9 +13,9 @@ false null false -# null -# 42 -# null +null +42 +null 1 null @@ -41,7 +41,9 @@ null null {"a":1} -# FIXME: string literals +{a,b,(.d):.a,e:.b} +{"a":1, "b":2, "c":3, "d":"c"} +{"a":1, "b":2, "c":1, "e":2} # # Field access, piping From e6a85737daaefd0066b684ff6fd3d3c5a60b0ac0 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sun, 9 Sep 2012 15:35:34 +0100 Subject: [PATCH 045/284] Print bad number values (Inf,NaN) "correctly". --- c/jv_print.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/c/jv_print.c b/c/jv_print.c index c9808ea7..c2f7f58d 100644 --- a/c/jv_print.c +++ b/c/jv_print.c @@ -67,6 +67,9 @@ static void jv_dump_string(jv str, int ascii_only) { static void jv_dump_term(struct dtoa_context* C, jv x) { char buf[JVP_DTOA_FMT_MAX_LEN]; switch (jv_get_kind(x)) { + case JV_KIND_INVALID: + assert(0 && "Invalid value"); + break; case JV_KIND_NULL: printf("null"); break; @@ -76,9 +79,19 @@ static void jv_dump_term(struct dtoa_context* C, jv x) { case JV_KIND_TRUE: printf("true"); break; - case JV_KIND_NUMBER: - printf("%s", jvp_dtoa_fmt(C, buf, jv_number_value(x))); + case JV_KIND_NUMBER: { + double d = jv_number_value(x); + if (d != d) { + // JSON doesn't have NaN, so we'll render it as "null" + printf("null"); + } else { + // Normalise infinities to something we can print in valid JSON + if (d > DBL_MAX) d = DBL_MAX; + if (d < -DBL_MAX) d = -DBL_MAX; + printf("%s", jvp_dtoa_fmt(C, buf, d)); + } break; + } case JV_KIND_STRING: // FIXME: all sorts of broken putchar('"'); From a4ff3d4670b6a64f41569fa0f7ae1fba0781625f Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sun, 9 Sep 2012 18:09:05 +0100 Subject: [PATCH 046/284] Bugfix for expanding objects. --- c/jv.c | 13 +++++++++---- c/jv.h | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/c/jv.c b/c/jv.c index c4a5af1c..1d5c9816 100644 --- a/c/jv.c +++ b/c/jv.c @@ -58,6 +58,10 @@ jv jv_null() { return JV_NULL; } +jv jv_bool(int x) { + return x ? JV_TRUE : JV_FALSE; +} + /* * Numbers */ @@ -617,11 +621,12 @@ static jv* jvp_object_write(jv_complex* object, jvp_string* key) { if (slot) { // already has the key jvp_string_free_p(key); - } else { - slot = jvp_object_add_slot(object, key, bucket); - slot->value = jv_invalid(); + return &slot->value; } - if (slot == 0) { + slot = jvp_object_add_slot(object, key, bucket); + if (slot) { + slot->value = jv_invalid(); + } else { jvp_object_rehash(object); bucket = jvp_object_find_bucket(object, key); assert(!jvp_object_find_slot(object, key, bucket)); diff --git a/c/jv.h b/c/jv.h index 8d9ebadb..6872ec5c 100644 --- a/c/jv.h +++ b/c/jv.h @@ -52,6 +52,7 @@ jv jv_invalid(); jv jv_null(); jv jv_true(); jv jv_false(); +jv jv_bool(int); jv jv_number(double); double jv_number_value(jv); From e258d20ba203adb1e91969a593c036179475deb6 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sun, 9 Sep 2012 19:17:07 +0100 Subject: [PATCH 047/284] Make the '+' operator merge objects. --- c/builtin.c | 2 ++ c/jv.c | 10 ++++++++++ c/jv.h | 6 ++++++ c/testdata | 4 ++++ 4 files changed, 22 insertions(+) diff --git a/c/builtin.c b/c/builtin.c index 35e15471..26698680 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -24,6 +24,8 @@ static void f_plus(jv input[], jv output[]) { jv_number_value(b)); } else if (jv_get_kind(a) == JV_KIND_ARRAY && jv_get_kind(b) == JV_KIND_ARRAY) { output[0] = jv_array_concat(a, b); + } else if (jv_get_kind(a) == JV_KIND_OBJECT && jv_get_kind(b) == JV_KIND_OBJECT) { + output[0] = jv_object_merge(a, b); } else { output[0] = jv_string("wtf gaize"); jv_free(a); diff --git a/c/jv.c b/c/jv.c index 1d5c9816..762bad89 100644 --- a/c/jv.c +++ b/c/jv.c @@ -729,6 +729,16 @@ int jv_object_length(jv object) { return n; } +jv jv_object_merge(jv a, jv b) { + assert(jv_get_kind(a) == JV_KIND_OBJECT); + jv_object_foreach(i, b) { + a = jv_object_set(a, + jv_object_iter_key(b, i), + jv_object_iter_value(b, i)); + } + return a; +} + /* * Object iteration (internal helpers) */ diff --git a/c/jv.h b/c/jv.h index 6872ec5c..2ec18629 100644 --- a/c/jv.h +++ b/c/jv.h @@ -78,12 +78,18 @@ jv jv_object_get(jv object, jv key); jv jv_object_set(jv object, jv key, jv value); jv jv_object_delete(jv object, jv key); int jv_object_length(jv object); +jv jv_object_merge(jv, jv); int jv_object_iter(jv); int jv_object_iter_next(jv, int); int jv_object_iter_valid(jv, int); jv jv_object_iter_key(jv, int); jv jv_object_iter_value(jv, int); +#define jv_object_foreach(i,t) \ + for (int i = jv_object_iter(t); \ + jv_object_iter_valid(t, i); \ + i = jv_object_iter_next(t, i)) \ + int jv_get_refcnt(jv); diff --git a/c/testdata b/c/testdata index 5aa3efed..f80249e4 100644 --- a/c/testdata +++ b/c/testdata @@ -155,6 +155,10 @@ null null [1,2,3,null] +{"a":1} + {"b":2} + {"c":3} +"asdfasdf" +{"a":1, "b":2, "c":3} + # # User-defined functions # Oh god. From c2593dc417fb23b5410f7f0f99a5a570ced6f658 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 10 Sep 2012 10:23:15 +0100 Subject: [PATCH 048/284] Make a main program that doesn't spam debugging info. --- c/Makefile | 5 ++++- c/execute.c | 28 +++++++++++++++++++--------- c/main.c | 2 -- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/c/Makefile b/c/Makefile index 2c4379de..cad23302 100644 --- a/c/Makefile +++ b/c/Makefile @@ -22,7 +22,10 @@ parser.tab.h: parser.tab.c jv_unicode.c: jv_utf8_tables.h parsertest: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c - $(CC) -o $@ $^ + $(CC) -DJQ_DEBUG=1 -o $@ $^ + +jq: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c + $(CC) -DJQ_DEBUG=0 -o $@ $^ jv_test: jv_test.c jv.c jv_print.c jv_dtoa.c $(CC) -DNO_JANSSON -o $@ $^ diff --git a/c/execute.c b/c/execute.c index 5e6a2c51..62984ca4 100644 --- a/c/execute.c +++ b/c/execute.c @@ -148,10 +148,10 @@ jv jq_next() { int backtracking = 0; while (1) { + uint16_t opcode = *pc; + +#if JQ_DEBUG dump_operation(frame_current_bytecode(&frame_stk), pc); - - uint16_t opcode = *pc++; - printf("\t"); const struct opcode_description* opdesc = opcode_describe(opcode); data_stk_elem* param; @@ -167,13 +167,15 @@ jv jq_next() { printf("<%d>", jv_get_refcnt(param->sv.value)); } + if (backtracking) printf("\t"); + + printf("\n"); +#endif if (backtracking) { - printf("\t"); opcode = ON_BACKTRACK(opcode); backtracking = 0; } - - printf("\n"); + pc++; switch (opcode) { default: assert(0 && "invalid instruction"); @@ -235,9 +237,11 @@ jv jq_next() { uint16_t v = *pc++; frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); jv* var = frame_local_var(fp, v); + #if JQ_DEBUG printf("V%d = ", v); jv_dump(jv_copy(*var)); printf("\n"); + #endif stack_push(stackval_replace(stack_pop(), jv_copy(*var))); break; } @@ -248,9 +252,11 @@ jv jq_next() { frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); jv* var = frame_local_var(fp, v); stackval val = stack_pop(); + #if JQ_DEBUG printf("V%d = ", v); jv_dump(jv_copy(val.value)); printf("\n"); + #endif jv_free(*var); *var = val.value; break; @@ -368,7 +374,6 @@ jv jq_next() { stackval top = stack_pop(); cfunc_input[0] = top.value; struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++]; - printf(" call %s\n", func->name); func->fptr(cfunc_input, cfunc_output); top.value = cfunc_output[0]; stack_push(top); @@ -386,7 +391,6 @@ jv jq_next() { cfunc_input[1] = a; cfunc_input[2] = b; struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++]; - printf(" call %s\n", func->name); func->fptr(cfunc_input, cfunc_output); top.value = cfunc_output[0]; stack_push(top); @@ -450,7 +454,11 @@ void jq_teardown() { } void run_program(struct bytecode* bc) { - char buf[4096]; +#if JQ_DEBUG + dump_disassembly(0, bc); + printf("\n"); +#endif + char buf[409600]; fgets(buf, sizeof(buf), stdin); jq_init(bc, jv_parse(buf)); jv result; @@ -458,6 +466,8 @@ void run_program(struct bytecode* bc) { jv_dump(result); printf("\n"); } + #if JQ_DEBUG printf("end of results\n"); + #endif jq_teardown(); } diff --git a/c/main.c b/c/main.c index b71bcad5..7e274c4a 100644 --- a/c/main.c +++ b/c/main.c @@ -88,8 +88,6 @@ int main(int argc, char* argv[]) { blk = gen_cbinding(&builtins, blk); struct bytecode* bc = block_compile(blk); block_free(blk); - dump_disassembly(0, bc); - printf("\n"); run_program(bc); bytecode_free(bc); } From 5c25c906576692c1d08e02e4a5fc0c5dca3a5f96 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 10 Sep 2012 13:06:46 +0100 Subject: [PATCH 049/284] When comparing two objects for equality, we don't need to recurse into e.g. array elements if the two objects are the same array. --- c/jv.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/c/jv.c b/c/jv.c index 762bad89..35ade789 100644 --- a/c/jv.c +++ b/c/jv.c @@ -824,23 +824,23 @@ int jv_equal(jv a, jv b) { int r; if (jv_get_kind(a) != jv_get_kind(b)) { r = 0; + } else if (jv_get_kind(a) == JV_KIND_NUMBER) { + r = jv_number_value(a) == jv_number_value(b); + } else if (a.val.complex.ptr == b.val.complex.ptr && + a.val.complex.i[0] == b.val.complex.i[0] && + a.val.complex.i[1] == b.val.complex.i[1]) { + r = 1; } else { switch (jv_get_kind(a)) { - case JV_KIND_NUMBER: - r = jv_number_value(a) == jv_number_value(b); - break; - case JV_KIND_ARRAY: { + case JV_KIND_ARRAY: r = jvp_array_equal(&a.val.complex, &b.val.complex); break; - } - case JV_KIND_STRING: { + case JV_KIND_STRING: r = jvp_string_equal(&a.val.complex, &b.val.complex); break; - } - case JV_KIND_OBJECT: { + case JV_KIND_OBJECT: r = jvp_object_equal(&a.val.complex, &b.val.complex); break; - } default: r = 1; break; From 649cac791a1c7046b4441fe63526af5ca20825ff Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 10 Sep 2012 15:04:19 +0100 Subject: [PATCH 050/284] Make jv_invalid() first-class values capable of holding an error. --- c/execute.c | 1 + c/jv.c | 47 +++++++++++++++++++++++++++++++++++++++++------ c/jv.h | 11 +++++++---- c/jv_parse.c | 37 ++++++++++++++++++------------------- c/jv_parse.h | 1 - c/main.c | 3 +++ 6 files changed, 70 insertions(+), 30 deletions(-) diff --git a/c/execute.c b/c/execute.c index 62984ca4..c8505bf6 100644 --- a/c/execute.c +++ b/c/execute.c @@ -466,6 +466,7 @@ void run_program(struct bytecode* bc) { jv_dump(result); printf("\n"); } + jv_free(result); #if JQ_DEBUG printf("end of results\n"); #endif diff --git a/c/jv.c b/c/jv.c index 35ade789..be50c6f6 100644 --- a/c/jv.c +++ b/c/jv.c @@ -37,15 +37,10 @@ jv_kind jv_get_kind(jv x) { return x.kind; } -static const jv JV_INVALID = {JV_KIND_INVALID, {0}}; static const jv JV_NULL = {JV_KIND_NULL, {0}}; static const jv JV_FALSE = {JV_KIND_FALSE, {0}}; static const jv JV_TRUE = {JV_KIND_TRUE, {0}}; -jv jv_invalid() { - return JV_INVALID; -} - jv jv_true() { return JV_TRUE; } @@ -62,6 +57,43 @@ jv jv_bool(int x) { return x ? JV_TRUE : JV_FALSE; } +/* + * Invalid objects, with optional error messages + */ + +typedef struct { + jv_refcnt refcnt; + jv errmsg; +} jvp_invalid; + +jv jv_invalid_with_msg(jv err) { + jv x; + x.kind = JV_KIND_INVALID; + x.val.complex.i[0] = x.val.complex.i[1] = 0; + jvp_invalid* i = malloc(sizeof(jvp_invalid)); + x.val.complex.ptr = &i->refcnt; + i->refcnt.count = 1; + i->errmsg = err; + return x; +} + +jv jv_invalid() { + return jv_invalid_with_msg(jv_null()); +} + +jv jv_invalid_get_message(jv inv) { + jv x = ((jvp_invalid*)inv.val.complex.ptr)->errmsg; + jv_free(inv); + return x; +} + +static void jvp_invalid_free(jv_complex* x) { + if (jvp_refcnt_dec(x)) { + jv_free(((jvp_invalid*)x->ptr)->errmsg); + free(x->ptr); + } +} + /* * Numbers */ @@ -789,7 +821,8 @@ jv jv_object_iter_value(jv object, int iter) { jv jv_copy(jv j) { if (jv_get_kind(j) == JV_KIND_ARRAY || jv_get_kind(j) == JV_KIND_STRING || - jv_get_kind(j) == JV_KIND_OBJECT) { + jv_get_kind(j) == JV_KIND_OBJECT || + jv_get_kind(j) == JV_KIND_INVALID) { jvp_refcnt_inc(&j.val.complex); } return j; @@ -802,6 +835,8 @@ void jv_free(jv j) { jvp_string_free(&j.val.complex); } else if (jv_get_kind(j) == JV_KIND_OBJECT) { jvp_object_free(&j.val.complex); + } else if (jv_get_kind(j) == JV_KIND_INVALID) { + jvp_invalid_free(&j.val.complex); } } diff --git a/c/jv.h b/c/jv.h index 2ec18629..a3a5e794 100644 --- a/c/jv.h +++ b/c/jv.h @@ -14,8 +14,8 @@ typedef enum { JV_KIND_TRUE, JV_KIND_NUMBER, JV_KIND_STRING, - JV_KIND_OBJECT, - JV_KIND_ARRAY + JV_KIND_ARRAY, + JV_KIND_OBJECT } jv_kind; typedef struct { @@ -49,6 +49,9 @@ void jv_free(jv); int jv_equal(jv, jv); jv jv_invalid(); +jv jv_invalid_with_msg(jv); +jv jv_invalid_get_msg(jv); + jv jv_null(); jv jv_true(); jv jv_false(); @@ -99,19 +102,19 @@ jv jv_parse(const char* string); jv jv_parse_sized(const char* string, int length); - - static jv jv_lookup(jv t, jv k) { jv v; if (jv_get_kind(t) == JV_KIND_OBJECT && jv_get_kind(k) == JV_KIND_STRING) { v = jv_object_get(t, k); if (!jv_is_valid(v)) { + jv_free(v); v = jv_null(); } } else if (jv_get_kind(t) == JV_KIND_ARRAY && jv_get_kind(k) == JV_KIND_NUMBER) { // FIXME: don't do lookup for noninteger index v = jv_array_get(t, (int)jv_number_value(k)); if (!jv_is_valid(v)) { + jv_free(v); v = jv_null(); } } else if (jv_get_kind(t) == JV_KIND_NULL && diff --git a/c/jv_parse.c b/c/jv_parse.c index 7a8c811e..9300f311 100644 --- a/c/jv_parse.c +++ b/c/jv_parse.c @@ -18,8 +18,7 @@ typedef const char* presult; void jv_parser_init(struct jv_parser* p) { p->stack = 0; p->stacklen = p->stackpos = 0; - p->hasnext = 0; - p->next = jv_invalid(); //FIXME: jv_invalid + p->next = jv_invalid(); p->tokenbuf = 0; p->tokenlen = p->tokenpos = 0; p->st = JV_PARSER_NORMAL; @@ -27,15 +26,15 @@ void jv_parser_init(struct jv_parser* p) { } void jv_parser_free(struct jv_parser* p) { - if (p->hasnext) jv_free(p->next); + jv_free(p->next); free(p->stack); free(p->tokenbuf); jvp_dtoa_context_free(&p->dtoa); } static pfunc value(struct jv_parser* p, jv val) { - if (p->hasnext) return "Expected separator between values"; - p->hasnext = 1; + if (jv_is_valid(p->next)) return "Expected separator between values"; + jv_free(p->next); p->next = val; return 0; } @@ -53,40 +52,40 @@ static void push(struct jv_parser* p, jv v) { static pfunc token(struct jv_parser* p, char ch) { switch (ch) { case '[': - if (p->hasnext) return "Expected separator between values"; + if (jv_is_valid(p->next)) return "Expected separator between values"; push(p, jv_array()); break; case '{': - if (p->hasnext) return "Expected separator between values"; + if (jv_is_valid(p->next)) return "Expected separator between values"; push(p, jv_object()); break; case ':': - if (!p->hasnext) + if (!jv_is_valid(p->next)) return "Expected string key before ':'"; if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) return "':' not as part of an object"; if (jv_get_kind(p->next) != JV_KIND_STRING) return "Object keys must be strings"; push(p, p->next); - p->hasnext = 0; + p->next = jv_invalid(); break; case ',': - if (!p->hasnext) + if (!jv_is_valid(p->next)) return "Expected value before ','"; if (p->stackpos == 0) return "',' not as part of an object or array"; if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_ARRAY) { p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); - p->hasnext = 0; + p->next = jv_invalid(); } else if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_STRING) { assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], p->stack[p->stackpos-1], p->next); p->stackpos--; - p->hasnext = 0; + p->next = jv_invalid(); } else { // this case hits on input like {"a", "b"} return "Objects must consist of key:value pairs"; @@ -96,37 +95,37 @@ static pfunc token(struct jv_parser* p, char ch) { case ']': if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_ARRAY) return "Unmatched ']'"; - if (p->hasnext) { + if (jv_is_valid(p->next)) { p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); - p->hasnext = 0; + p->next = jv_invalid(); } else { if (jv_array_length(jv_copy(p->stack[p->stackpos-1])) != 0) { // this case hits on input like [1,2,3,] return "Expected another array element"; } } - p->hasnext = 1; + jv_free(p->next); p->next = p->stack[--p->stackpos]; break; case '}': if (p->stackpos == 0) return "Unmatched '}'"; - if (p->hasnext) { + if (jv_is_valid(p->next)) { if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_STRING) return "Objects must consist of key:value pairs"; assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], p->stack[p->stackpos-1], p->next); p->stackpos--; - p->hasnext = 0; + p->next = jv_invalid(); } else { if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) return "Unmatched '}'"; if (jv_object_length(jv_copy(p->stack[p->stackpos-1])) != 0) return "Expected another key-value pair"; } - p->hasnext = 1; + jv_free(p->next); p->next = p->stack[--p->stackpos]; break; } @@ -320,7 +319,7 @@ static pfunc finish(struct jv_parser* p) { return "Unfinished JSON term"; // this will happen on the empty string - if (!p->hasnext) + if (!jv_is_valid(p->next)) return "Expected JSON value"; return 0; diff --git a/c/jv_parse.h b/c/jv_parse.h index 4dddcf6f..10270766 100644 --- a/c/jv_parse.h +++ b/c/jv_parse.h @@ -4,7 +4,6 @@ struct jv_parser { int stackpos; int stacklen; jv next; - int hasnext; char* tokenbuf; int tokenpos; diff --git a/c/main.c b/c/main.c index 7e274c4a..7c341d8d 100644 --- a/c/main.c +++ b/c/main.c @@ -49,6 +49,7 @@ void run_tests() { assert(jv_is_valid(expected)); jv actual = jq_next(); if (!jv_is_valid(actual)) { + jv_free(actual); printf("Insufficient results\n"); pass = 0; break; @@ -70,6 +71,8 @@ void run_tests() { jv_dump(extra); printf("\n"); pass = 0; + } else { + jv_free(extra); } } jq_teardown(); From 0159c0ecc58f439e976ba987e826155859c979f5 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 10 Sep 2012 15:08:39 +0100 Subject: [PATCH 051/284] Plug a memory leak in jv_object_merge --- c/jv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/c/jv.c b/c/jv.c index be50c6f6..53e2ef7d 100644 --- a/c/jv.c +++ b/c/jv.c @@ -768,6 +768,7 @@ jv jv_object_merge(jv a, jv b) { jv_object_iter_key(b, i), jv_object_iter_value(b, i)); } + jv_free(b); return a; } From a3e509034b4eada3903fc8e5cdcdf253c207b4b8 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 10 Sep 2012 16:01:56 +0100 Subject: [PATCH 052/284] jv_string_fmt (create printf-formatted JSON strings) --- c/Makefile | 2 +- c/jv.c | 24 ++++++++++++++++++++++-- c/jv.h | 1 + c/jv_test.c | 9 +++++++++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/c/Makefile b/c/Makefile index cad23302..c80642dc 100644 --- a/c/Makefile +++ b/c/Makefile @@ -27,7 +27,7 @@ parsertest: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute jq: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c $(CC) -DJQ_DEBUG=0 -o $@ $^ -jv_test: jv_test.c jv.c jv_print.c jv_dtoa.c +jv_test: jv_test.c jv.c jv_print.c jv_dtoa.c jv_unicode.c $(CC) -DNO_JANSSON -o $@ $^ jv_parse: jv_parse.c jv.c jv_print.c jv_dtoa.c diff --git a/c/jv.c b/c/jv.c index 53e2ef7d..73805a0a 100644 --- a/c/jv.c +++ b/c/jv.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "jv.h" @@ -81,8 +82,8 @@ jv jv_invalid() { return jv_invalid_with_msg(jv_null()); } -jv jv_invalid_get_message(jv inv) { - jv x = ((jvp_invalid*)inv.val.complex.ptr)->errmsg; +jv jv_invalid_get_msg(jv inv) { + jv x = jv_copy(((jvp_invalid*)inv.val.complex.ptr)->errmsg); jv_free(inv); return x; } @@ -472,6 +473,25 @@ const char* jv_string_value(jv j) { return jvp_string_ptr(&j.val.complex)->data; } +jv jv_string_fmt(const char* fmt, ...) { + int size = 1024; + while (1) { + char* buf = malloc(size); + va_list args; + va_start(args, fmt); + int n = vsnprintf(buf, size, fmt, args); + va_end(args); + if (n < size) { + jv ret = jv_string_sized(buf, n); + free(buf); + return ret; + } else { + free(buf); + size = n * 2; + } + } +} + /* * Objects (internal helpers) */ diff --git a/c/jv.h b/c/jv.h index a3a5e794..c415ee28 100644 --- a/c/jv.h +++ b/c/jv.h @@ -75,6 +75,7 @@ jv jv_string_sized(const char*, int); int jv_string_length(jv); uint32_t jv_string_hash(jv); const char* jv_string_value(jv); +jv jv_string_fmt(const char*, ...); jv jv_object(); jv jv_object_get(jv object, jv key); diff --git a/c/jv_test.c b/c/jv_test.c index 2b5a6276..725e5aba 100644 --- a/c/jv_test.c +++ b/c/jv_test.c @@ -108,6 +108,15 @@ int main(){ jv_free(a1); jv_free(a2); jv_free(b); + + assert(jv_equal(jv_string("hello42!"), jv_string_fmt("hello%d%s", 42, "!"))); + char big[20000]; + for (int i=0; i Date: Mon, 10 Sep 2012 16:07:03 +0100 Subject: [PATCH 053/284] Sensible error messages when a silly addition is performed. Fix a test to no longer perform an invalid addition. --- c/builtin.c | 4 +++- c/execute.c | 22 ++++++++++++++++++++-- c/jv.c | 15 +++++++++++++++ c/jv.h | 1 + c/testdata | 2 +- 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/c/builtin.c b/c/builtin.c index 26698680..45056fc0 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -27,7 +27,9 @@ static void f_plus(jv input[], jv output[]) { } else if (jv_get_kind(a) == JV_KIND_OBJECT && jv_get_kind(b) == JV_KIND_OBJECT) { output[0] = jv_object_merge(a, b); } else { - output[0] = jv_string("wtf gaize"); + output[0] = jv_invalid_with_msg(jv_string_fmt("Attempted to add %s and %s", + jv_kind_name(jv_get_kind(a)), + jv_kind_name(jv_get_kind(b)))); jv_free(a); jv_free(b); } diff --git a/c/execute.c b/c/execute.c index c8505bf6..f59e156e 100644 --- a/c/execute.c +++ b/c/execute.c @@ -376,7 +376,16 @@ jv jq_next() { struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++]; func->fptr(cfunc_input, cfunc_output); top.value = cfunc_output[0]; - stack_push(top); + if (jv_is_valid(top.value)) { + stack_push(top); + } else { + jv msg = jv_invalid_get_msg(top.value); + if (jv_get_kind(msg) == JV_KIND_STRING) { + fprintf(stderr, "jq: error: %s\n", jv_string_value(msg)); + } + jv_free(msg); + goto do_backtrack; + } break; } @@ -393,7 +402,16 @@ jv jq_next() { struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++]; func->fptr(cfunc_input, cfunc_output); top.value = cfunc_output[0]; - stack_push(top); + if (jv_is_valid(top.value)) { + stack_push(top); + } else { + jv msg = jv_invalid_get_msg(top.value); + if (jv_get_kind(msg) == JV_KIND_STRING) { + fprintf(stderr, "jq: error: %s\n", jv_string_value(msg)); + } + jv_free(msg); + goto do_backtrack; + } break; } diff --git a/c/jv.c b/c/jv.c index 73805a0a..8c0c0348 100644 --- a/c/jv.c +++ b/c/jv.c @@ -38,6 +38,21 @@ jv_kind jv_get_kind(jv x) { return x.kind; } +const char* jv_kind_name(jv_kind k) { + switch (k) { + case JV_KIND_INVALID: return ""; + case JV_KIND_NULL: return "null"; + case JV_KIND_FALSE: return "boolean"; + case JV_KIND_TRUE: return "boolean"; + case JV_KIND_NUMBER: return "number"; + case JV_KIND_STRING: return "string"; + case JV_KIND_ARRAY: return "array"; + case JV_KIND_OBJECT: return "object"; + } + assert(0); + return ""; +} + static const jv JV_NULL = {JV_KIND_NULL, {0}}; static const jv JV_FALSE = {JV_KIND_FALSE, {0}}; static const jv JV_TRUE = {JV_KIND_TRUE, {0}}; diff --git a/c/jv.h b/c/jv.h index c415ee28..9aadd418 100644 --- a/c/jv.h +++ b/c/jv.h @@ -41,6 +41,7 @@ typedef struct { */ jv_kind jv_get_kind(jv); +const char* jv_kind_name(jv_kind); static int jv_is_valid(jv x) { return jv_get_kind(x) != JV_KIND_INVALID; } jv jv_copy(jv); diff --git a/c/testdata b/c/testdata index f80249e4..11684dde 100644 --- a/c/testdata +++ b/c/testdata @@ -207,7 +207,7 @@ def id(x):x; 2000 as $x | def f(x):1 as $x | id([$x, x, x]); def g(x): 100 as $x # test backtracking through function calls and returns # this test is *evil* [[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | g; f[0] | [f][0][1] | f] -"woo, testing!" +999999999 [[110.0, 130.0], [210.0, 130.0], [110.0, 230.0], [210.0, 230.0], [120.0, 160.0], [220.0, 160.0], [120.0, 260.0], [220.0, 260.0]] # From 65ce73deb4eab4ef6d83a0ad44c603d6286e964d Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 10 Sep 2012 16:16:39 +0100 Subject: [PATCH 054/284] String concatenation. --- c/builtin.c | 2 ++ c/jv.c | 21 +++++++++++++++++++++ c/jv.h | 1 + c/testdata | 8 ++++++++ 4 files changed, 32 insertions(+) diff --git a/c/builtin.c b/c/builtin.c index 45056fc0..bdca2540 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -22,6 +22,8 @@ static void f_plus(jv input[], jv output[]) { if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { output[0] = jv_number(jv_number_value(a) + jv_number_value(b)); + } else if (jv_get_kind(a) == JV_KIND_STRING && jv_get_kind(b) == JV_KIND_STRING) { + output[0] = jv_string_concat(a, b); } else if (jv_get_kind(a) == JV_KIND_ARRAY && jv_get_kind(b) == JV_KIND_ARRAY) { output[0] = jv_array_concat(a, b); } else if (jv_get_kind(a) == JV_KIND_OBJECT && jv_get_kind(b) == JV_KIND_OBJECT) { diff --git a/c/jv.c b/c/jv.c index 8c0c0348..f8b79ce6 100644 --- a/c/jv.c +++ b/c/jv.c @@ -355,6 +355,7 @@ static jv_complex jvp_string_new(const char* data, uint32_t length) { return r; } + static void jvp_string_free(jv_complex* s) { if (jvp_refcnt_dec(s)) { jvp_string* str = jvp_string_ptr(s); @@ -377,6 +378,16 @@ static uint32_t jvp_string_length(jvp_string* s) { return s->length_hashed >> 1; } +static jv_complex jvp_string_concat(jvp_string* a, jvp_string* b) { + uint32_t la = jvp_string_length(a), lb = jvp_string_length(b); + jvp_string* s = jvp_string_alloc(la + lb); + memcpy(s->data, a->data, la); + memcpy(s->data + la, b->data, lb); + s->data[la + lb] = 0; + jv_complex r = {&s->refcnt, {0,0}}; + return r; +} + static const uint32_t HASH_SEED = 0x432A9843; static uint32_t rotl32 (uint32_t x, int8_t r){ @@ -488,6 +499,16 @@ const char* jv_string_value(jv j) { return jvp_string_ptr(&j.val.complex)->data; } +jv jv_string_concat(jv a, jv b) { + jv j; + j.kind = JV_KIND_STRING; + j.val.complex = jvp_string_concat(jvp_string_ptr(&a.val.complex), + jvp_string_ptr(&b.val.complex)); + jv_free(a); + jv_free(b); + return j; +} + jv jv_string_fmt(const char* fmt, ...) { int size = 1024; while (1) { diff --git a/c/jv.h b/c/jv.h index 9aadd418..ef64816c 100644 --- a/c/jv.h +++ b/c/jv.h @@ -76,6 +76,7 @@ jv jv_string_sized(const char*, int); int jv_string_length(jv); uint32_t jv_string_hash(jv); const char* jv_string_value(jv); +jv jv_string_concat(jv, jv); jv jv_string_fmt(const char*, ...); jv jv_object(); diff --git a/c/testdata b/c/testdata index 11684dde..c353dc2f 100644 --- a/c/testdata +++ b/c/testdata @@ -159,6 +159,14 @@ null "asdfasdf" {"a":1, "b":2, "c":3} +"asdf" + "jkl;" + . +"some string" +"asdfjkl;some string" + +"\u0000\u0020\u0000" + . +"\u0000\u0020\u0000" +"\u0000 \u0000\u0000 \u0000" + # # User-defined functions # Oh god. From 6f3abbac620132260d5424dbee259f850dad890f Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 10 Sep 2012 16:49:25 +0100 Subject: [PATCH 055/284] Subtraction - as expected for numbers, ruby-style set diff for arrays. --- c/builtin.c | 34 ++++++++++++++++++++++++++++++++++ c/lexer.l | 2 +- c/parser.y | 28 +++++++++++++++++++++------- c/testdata | 8 ++++++++ 4 files changed, 64 insertions(+), 8 deletions(-) diff --git a/c/builtin.c b/c/builtin.c index bdca2540..65ecb52c 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -37,10 +37,44 @@ static void f_plus(jv input[], jv output[]) { } } +static void f_minus(jv input[], jv output[]) { + jv_free(input[0]); + jv a = input[2]; + jv b = input[1]; + if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { + output[0] = jv_number(jv_number_value(a) - jv_number_value(b)); + } else if (jv_get_kind(a) == JV_KIND_ARRAY && jv_get_kind(b) == JV_KIND_ARRAY) { + jv out = jv_array(); + for (int i=0; i Exp Term MkDict MkDictPair ExpD ElseBody - %{ #include "lexer.yy.h" void yyerror(YYLTYPE* loc, block* answer, yyscan_t lexer, const char *s){ @@ -64,6 +63,21 @@ static block gen_index(block obj, block key) { return block_join(obj, block_join(gen_subexp(key), gen_op_simple(INDEX))); } +static block gen_binop(block a, block b, char op) { + const char* funcname = 0; + switch (op) { + case '+': funcname = "_plus"; break; + case '-': funcname = "_minus"; break; + } + assert(funcname); + + block c = gen_noop(); + block_append(&c, gen_subexp(a)); + block_append(&c, gen_subexp(b)); + block_append(&c, gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, funcname))); + return c; +} + %} %% @@ -136,10 +150,11 @@ Exp ',' Exp { } | Exp '+' Exp { - $$ = gen_noop(); - block_append(&$$, gen_subexp($1)); - block_append(&$$, gen_subexp($3)); - block_append(&$$, gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, "_plus"))); + $$ = gen_binop($1, $3, '+'); +} | + +Exp '-' Exp { + $$ = gen_binop($1, $3, '-'); } | Term { @@ -154,7 +169,6 @@ ElseBody: $$ = $2; } - ExpD: ExpD '|' ExpD { $$ = block_join($1, $3); diff --git a/c/testdata b/c/testdata index c353dc2f..6386ac08 100644 --- a/c/testdata +++ b/c/testdata @@ -167,6 +167,14 @@ null "\u0000\u0020\u0000" "\u0000 \u0000\u0000 \u0000" +42 - . +11 +31 + +[1,2,3,4,1] - [.,3] +1 +[2,4] + # # User-defined functions # Oh god. From aa3ebdfe9b714548fb0d5cfe0265950b1392fb1e Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 10 Sep 2012 16:57:17 +0100 Subject: [PATCH 056/284] Multiplication and division operators. It is an error to use these on anything but numbers. Maybe later implementing python/ruby-style ("a" * 100) might be handy. --- c/builtin.c | 32 ++++++++++++++++++++++++++++++++ c/lexer.l | 2 +- c/parser.y | 11 +++++++++++ c/testdata | 8 ++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/c/builtin.c b/c/builtin.c index 65ecb52c..b65bb09b 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -70,11 +70,43 @@ static void f_minus(jv input[], jv output[]) { } } +static void f_multiply(jv input[], jv output[]) { + jv_free(input[0]); + jv a = input[2]; + jv b = input[1]; + if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { + output[0] = jv_number(jv_number_value(a) * jv_number_value(b)); + } else { + output[0] = jv_invalid_with_msg(jv_string_fmt("Attempted to multiply %s and %s", + jv_kind_name(jv_get_kind(a)), + jv_kind_name(jv_get_kind(b)))); + jv_free(a); + jv_free(b); + } +} + +static void f_divide(jv input[], jv output[]) { + jv_free(input[0]); + jv a = input[2]; + jv b = input[1]; + if (jv_get_kind(a) == JV_KIND_NUMBER && jv_get_kind(b) == JV_KIND_NUMBER) { + output[0] = jv_number(jv_number_value(a) / jv_number_value(b)); + } else { + output[0] = jv_invalid_with_msg(jv_string_fmt("Attempted to divide %s by %s", + jv_kind_name(jv_get_kind(a)), + jv_kind_name(jv_get_kind(b)))); + jv_free(a); + jv_free(b); + } +} + struct cfunction function_list[] = { {f_true, "true", CALL_BUILTIN_1_1}, {f_false, "false", CALL_BUILTIN_1_1}, {f_null, "null", CALL_BUILTIN_1_1}, {f_plus, "_plus", CALL_BUILTIN_3_1}, {f_minus, "_minus", CALL_BUILTIN_3_1}, + {f_multiply, "_multiply", CALL_BUILTIN_3_1}, + {f_divide, "_divide", CALL_BUILTIN_3_1}, }; struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; diff --git a/c/lexer.l b/c/lexer.l index 1b74d43f..1794b9f1 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -22,7 +22,7 @@ "not" { return NOT; } "end" { return END; } "//" { return DEFINEDOR; } -"."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"-"|"\$" { return yytext[0];} +"."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"-"|"*"|"/"|"\$" { return yytext[0];} \"(\\.|[^\\"])*\" | -?[0-9.]+([eE][+-]?[0-9]+)? { diff --git a/c/parser.y b/c/parser.y index 72b91a1a..225a324e 100644 --- a/c/parser.y +++ b/c/parser.y @@ -43,6 +43,7 @@ %left OR %left AND %left '+' '-' +%left '*' '/' %type Exp Term MkDict MkDictPair ExpD ElseBody @@ -68,6 +69,8 @@ static block gen_binop(block a, block b, char op) { switch (op) { case '+': funcname = "_plus"; break; case '-': funcname = "_minus"; break; + case '*': funcname = "_multiply"; break; + case '/': funcname = "_divide"; break; } assert(funcname); @@ -157,6 +160,14 @@ Exp '-' Exp { $$ = gen_binop($1, $3, '-'); } | +Exp '*' Exp { + $$ = gen_binop($1, $3, '*'); +} | + +Exp '/' Exp { + $$ = gen_binop($1, $3, '/'); +} | + Term { $$ = $1; } diff --git a/c/testdata b/c/testdata index 6386ac08..eb9f0c5f 100644 --- a/c/testdata +++ b/c/testdata @@ -175,6 +175,14 @@ null 1 [2,4] +[10 * 20, 20 / .] +4 +[200, 5] + +1 + 2 * 2 + 10 / 2 +null +10 + # # User-defined functions # Oh god. From 3895bbf85698ab3e9f739fc74957415a8788a559 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 10 Sep 2012 17:08:13 +0100 Subject: [PATCH 057/284] String -> number conversions with "tonumber". --- c/builtin.c | 25 +++++++++++++++++++++++++ c/testdata | 4 ++++ 2 files changed, 29 insertions(+) diff --git a/c/builtin.c b/c/builtin.c index b65bb09b..7943675d 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -100,6 +100,30 @@ static void f_divide(jv input[], jv output[]) { } } +static void f_tonumber(jv input[], jv output[]) { + if (jv_get_kind(input[0]) == JV_KIND_NUMBER) { + output[0] = input[0]; + } else if (jv_get_kind(input[0]) == JV_KIND_STRING) { + jv parsed = jv_parse(jv_string_value(input[0])); + if (!jv_is_valid(parsed)) { + jv_free(input[0]); + output[0] = parsed; + } else if (jv_get_kind(parsed) != JV_KIND_NUMBER) { + output[0] = jv_invalid_with_msg(jv_string_fmt("'%s' is not a number", + jv_string_value(input[0]))); + jv_free(input[0]); + } else { + jv_free(input[0]); + output[0] = parsed; + } + } else { + output[0] = jv_invalid_with_msg(jv_string_fmt("Cannot parse %s as a number", + jv_kind_name(jv_get_kind(input[0])))); + jv_free(input[0]); + return; + } +} + struct cfunction function_list[] = { {f_true, "true", CALL_BUILTIN_1_1}, {f_false, "false", CALL_BUILTIN_1_1}, @@ -108,5 +132,6 @@ struct cfunction function_list[] = { {f_minus, "_minus", CALL_BUILTIN_3_1}, {f_multiply, "_multiply", CALL_BUILTIN_3_1}, {f_divide, "_divide", CALL_BUILTIN_3_1}, + {f_tonumber, "tonumber", CALL_BUILTIN_1_1}, }; struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; diff --git a/c/testdata b/c/testdata index eb9f0c5f..45140242 100644 --- a/c/testdata +++ b/c/testdata @@ -183,6 +183,10 @@ null null 10 +1 + tonumber + ("10" | tonumber) +4 +15 + # # User-defined functions # Oh god. From 4d47f8f1e18125ffcffc8354b71a96c43f1f1473 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 10 Sep 2012 18:08:00 +0100 Subject: [PATCH 058/284] '==' operator, tests for equality and operator precedence. --- c/builtin.c | 6 ++++++ c/parser.y | 19 +++++++++++++------ c/testdata | 17 +++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/c/builtin.c b/c/builtin.c index 7943675d..375e3252 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -100,6 +100,11 @@ static void f_divide(jv input[], jv output[]) { } } +static void f_equal(jv input[], jv output[]) { + jv_free(input[0]); + output[0] = jv_bool(jv_equal(input[2], input[1])); +} + static void f_tonumber(jv input[], jv output[]) { if (jv_get_kind(input[0]) == JV_KIND_NUMBER) { output[0] = input[0]; @@ -133,5 +138,6 @@ struct cfunction function_list[] = { {f_multiply, "_multiply", CALL_BUILTIN_3_1}, {f_divide, "_divide", CALL_BUILTIN_3_1}, {f_tonumber, "tonumber", CALL_BUILTIN_1_1}, + {f_equal, "_equal", CALL_BUILTIN_3_1}, }; struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; diff --git a/c/parser.y b/c/parser.y index 225a324e..0f1e42c4 100644 --- a/c/parser.y +++ b/c/parser.y @@ -19,11 +19,6 @@ %token IDENT %token LITERAL - /* revolting hack */ -%left ';' - -%left '|' -%left ',' %token EQ "==" %token DEFINEDOR "//" %token AS "as" @@ -37,6 +32,12 @@ %token AND "and" %token OR "or" %token NOT "not" + + + /* revolting hack */ +%left ';' +%left '|' +%left ',' %right "//" %nonassoc '=' SETPIPE %nonassoc EQ @@ -64,13 +65,14 @@ static block gen_index(block obj, block key) { return block_join(obj, block_join(gen_subexp(key), gen_op_simple(INDEX))); } -static block gen_binop(block a, block b, char op) { +static block gen_binop(block a, block b, int op) { const char* funcname = 0; switch (op) { case '+': funcname = "_plus"; break; case '-': funcname = "_minus"; break; case '*': funcname = "_multiply"; break; case '/': funcname = "_divide"; break; + case EQ: funcname = "_equal"; break; } assert(funcname); @@ -129,6 +131,7 @@ Exp "and" Exp { $$ = gen_and($1, $3); } | + "not" Exp { $$ = gen_not($2); } | @@ -168,6 +171,10 @@ Exp '/' Exp { $$ = gen_binop($1, $3, '/'); } | +Exp "==" Exp { + $$ = gen_binop($1, $3, EQ); +} | + Term { $$ = $1; } diff --git a/c/testdata b/c/testdata index 45140242..bd1d7f25 100644 --- a/c/testdata +++ b/c/testdata @@ -183,10 +183,27 @@ null null 10 +[16 / 4 / 2, 16 / 4 * 2, 16 - 4 - 2, 16 - 4 + 2] +null +[2, 8, 10, 14] + 1 + tonumber + ("10" | tonumber) 4 15 +[{"a":42},.object,10,.num,false,true,null,"b",[1,4]] | .[] as $x | [$x == .[]] +{"object": {"a":42}, "num":10.0} +[true, true, false, false, false, false, false, false, false] +[true, true, false, false, false, false, false, false, false] +[false, false, true, true, false, false, false, false, false] +[false, false, true, true, false, false, false, false, false] +[false, false, false, false, true, false, false, false, false] +[false, false, false, false, false, true, false, false, false] +[false, false, false, false, false, false, true, false, false] +[false, false, false, false, false, false, false, true, false] +[false, false, false, false, false, false, false, false, true ] + + # # User-defined functions # Oh god. From 95dd64b0f0f5bcf1aff780caa229bc592703faa1 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 11 Sep 2012 00:04:47 +0100 Subject: [PATCH 059/284] Much, much better error reporting from the parser. Getting proper locations through flex/bison was more effort than was advertised. --- c/execute.c | 20 ----------------- c/jv_parse.c | 18 +++++++-------- c/lexer.l | 9 ++++++++ c/locfile.h | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ c/main.c | 39 +++++++++++++++++++++++++++++---- c/parser.y | 59 ++++++++++++++++++++++++++++++++++++++++--------- 6 files changed, 163 insertions(+), 44 deletions(-) create mode 100644 c/locfile.h diff --git a/c/execute.c b/c/execute.c index f59e156e..9f7b63b5 100644 --- a/c/execute.c +++ b/c/execute.c @@ -470,23 +470,3 @@ void jq_teardown() { pathbuf = 0; pathsize = 0; } - -void run_program(struct bytecode* bc) { -#if JQ_DEBUG - dump_disassembly(0, bc); - printf("\n"); -#endif - char buf[409600]; - fgets(buf, sizeof(buf), stdin); - jq_init(bc, jv_parse(buf)); - jv result; - while (jv_is_valid(result = jq_next())) { - jv_dump(result); - printf("\n"); - } - jv_free(result); - #if JQ_DEBUG - printf("end of results\n"); - #endif - jq_teardown(); -} diff --git a/c/jv_parse.c b/c/jv_parse.c index 9300f311..7fd4d2d2 100644 --- a/c/jv_parse.c +++ b/c/jv_parse.c @@ -331,20 +331,18 @@ jv jv_parse_sized(const char* string, int length) { const char* p = string; char ch; - while (p < string + length) { + presult msg = 0; + while (msg == 0 && p < string + length) { ch = *p++; - presult msg = scan(&parser, ch); - if (msg){ - printf("ERROR: %s (parsing '%s')\n", msg, string); - return jv_invalid(); - } + msg = scan(&parser, ch); } - presult msg = finish(&parser); + if (msg == 0) msg = finish(&parser); + jv value; if (msg) { - printf("ERROR: %s (parsing '%s')\n", msg, string); - return jv_invalid(); + value = jv_invalid_with_msg(jv_string_fmt("%s (while parsing '%s')", msg, string)); + } else { + value = jv_copy(parser.next); } - jv value = jv_copy(parser.next); jv_parser_free(&parser); return value; } diff --git a/c/lexer.l b/c/lexer.l index 1794b9f1..bb7f57d6 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -1,10 +1,19 @@ %{ #include "compile.h" #include "parser.tab.h" /* Generated by bison. */ + +#define YY_USER_ACTION \ + do { \ + yylloc->start = yyget_extra(yyscanner); \ + yylloc->end = yylloc->start + yyleng; \ + yyset_extra(yylloc->end, yyscanner); \ + } while (0); + %} %option noyywrap nounput noinput nodefault %option reentrant +%option extra-type="int" %option bison-bridge bison-locations %% diff --git a/c/locfile.h b/c/locfile.h new file mode 100644 index 00000000..0f605bbb --- /dev/null +++ b/c/locfile.h @@ -0,0 +1,62 @@ +#include +#include +#include +typedef struct { + int start, end; +} location; + +struct locfile { + const char* data; + int length; + int* linemap; + int nlines; +}; + +static void locfile_init(struct locfile* l, const char* data, int length) { + l->data = data; + l->length = length; + l->nlines = 1; + for (int i=0; inlines++; + } + l->linemap = malloc(sizeof(int) * (l->nlines + 1)); + l->linemap[0] = 0; + int line = 1; + for (int i=0; ilinemap[line] = i; + line++; + } + } + l->linemap[l->nlines] = length; +} + +static void locfile_free(struct locfile* l) { + free(l->linemap); +} + +static int locfile_get_line(struct locfile* l, int pos) { + assert(pos < l->length); + int line = 0; + while (l->linemap[line+1] < pos) line++; + assert(line < l->nlines); + return line; +} + +static int locfile_line_length(struct locfile* l, int line) { + assert(line < l->nlines); + return l->linemap[line+1] - l->linemap[line]; +} + +static void locfile_locate(struct locfile* l, location loc) { + int startline = locfile_get_line(l, loc.start); + int offset = l->linemap[startline]; + printf("%.*s\n", locfile_line_length(l, startline), l->data + offset); + printf("%*s", loc.start - offset, ""); + for (int i = loc.start; + i < loc.end && i < offset + locfile_line_length(l, startline); + i++){ + printf("^"); + } + printf("\n"); +} diff --git a/c/main.c b/c/main.c index 7c341d8d..4faf2a0b 100644 --- a/c/main.c +++ b/c/main.c @@ -4,13 +4,36 @@ #include "builtin.h" #include "jv.h" -block compile(const char* str); +int compile(const char* str, block* answer); void jq_init(struct bytecode* bc, jv value); jv jq_next(); void jq_teardown(); -void run_program(struct bytecode* bc); + +void run_program(struct bytecode* bc) { +#if JQ_DEBUG + dump_disassembly(0, bc); + printf("\n"); +#endif + char buf[409600]; + fgets(buf, sizeof(buf), stdin); + jv value = jv_parse(buf); + if (!jv_is_valid(value)) { + assert(0 && "couldn't parse input"); //FIXME + } + jq_init(bc, value); + jv result; + while (jv_is_valid(result = jq_next())) { + jv_dump(result); + printf("\n"); + } + jv_free(result); + #if JQ_DEBUG + printf("end of results\n"); + #endif + jq_teardown(); +} int skipline(const char* buf) { int p = 0; @@ -29,7 +52,9 @@ void run_tests() { if (skipline(buf)) continue; printf("Testing %s\n", buf); int pass = 1; - block program = compile(buf); + block program; + int nerrors = compile(buf, &program); + assert(nerrors == 0); block_append(&program, gen_op_simple(YIELD)); block_append(&program, gen_op_simple(BACKTRACK)); program = gen_cbinding(&builtins, program); @@ -86,11 +111,17 @@ void run_tests() { int main(int argc, char* argv[]) { if (argc == 1) { run_tests(); return 0; } - block blk = compile(argv[1]); + block blk; + int nerrors = compile(argv[1], &blk); + if (nerrors > 0) { + printf("%d compile %s\n", nerrors, nerrors > 1 ? "errors" : "error"); + return 1; + } block_append(&blk, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK))); blk = gen_cbinding(&builtins, blk); struct bytecode* bc = block_compile(blk); block_free(blk); run_program(bc); bytecode_free(bc); + return 0; } diff --git a/c/parser.y b/c/parser.y index 0f1e42c4..11b88a7f 100644 --- a/c/parser.y +++ b/c/parser.y @@ -4,21 +4,40 @@ #include "compile.h" %} +%code requires { +#include "locfile.h" +#define YYLTYPE location +#define YYLLOC_DEFAULT(Loc, Rhs, N) \ + do { \ + if (N) { \ + (Loc).start = YYRHSLOC(Rhs, 1).start; \ + (Loc).end = YYRHSLOC(Rhs, N).end; \ + } else { \ + (Loc).start = YYRHSLOC(Rhs, 0).end; \ + (Loc).end = YYRHSLOC(Rhs, 0).end; \ + } \ + } while (0) + } + %locations +%error-verbose %define api.pure %union { jv literal; block blk; } +%destructor { jv_free($$); } +%destructor { block_free($$); } + %parse-param {block* answer} +%parse-param {int* errors} +%parse-param {struct locfile* locations} %parse-param {yyscan_t lexer} %lex-param {yyscan_t lexer} - %token IDENT %token LITERAL - %token EQ "==" %token DEFINEDOR "//" %token AS "as" @@ -50,8 +69,18 @@ %type Exp Term MkDict MkDictPair ExpD ElseBody %{ #include "lexer.yy.h" -void yyerror(YYLTYPE* loc, block* answer, yyscan_t lexer, const char *s){ - printf("ERROR: %s\n", s); +#define FAIL(loc, msg) \ + do { \ + location l = loc; \ + yyerror(&l, answer, errors, locations, lexer, msg); \ + /*YYERROR*/; \ + } while (0) + +void yyerror(YYLTYPE* loc, block* answer, int* errors, + struct locfile* locations, yyscan_t lexer, const char *s){ + (*errors)++; + printf("error: %s\n", s); + locfile_locate(locations, *loc); } static block gen_dictpair(block k, block v) { @@ -263,7 +292,9 @@ MkDictPair $$ = gen_dictpair(gen_op_const(LOADK, $1), $3); } | LITERAL ':' ExpD { - assert(jv_get_kind($1) == JV_KIND_STRING); + if (jv_get_kind($1) != JV_KIND_STRING) { + FAIL(@1, "Object keys must be strings"); + } $$ = gen_dictpair(gen_op_const(LOADK, $1), $3); } | IDENT { @@ -275,14 +306,22 @@ MkDictPair } %% -block compile(const char* str) { +int compile(const char* str, block* answer) { yyscan_t scanner; YY_BUFFER_STATE buf; - block answer = gen_noop(); - yylex_init(&scanner); + yylex_init_extra(0, &scanner); buf = yy_scan_string(str, scanner); - yyparse(&answer, scanner); + int errors = 0; + struct locfile locations; + locfile_init(&locations, str, strlen(str)); + *answer = gen_noop(); + yyparse(answer, &errors, &locations, scanner); + locfile_free(&locations); yy_delete_buffer(buf, scanner); yylex_destroy(scanner); - return answer; + if (errors > 0) { + block_free(*answer); + *answer = gen_noop(); + } + return errors; } From ac3f8bcc525510be5f1b73dc4e7904490dcb3ed4 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 11 Sep 2012 09:13:20 +0100 Subject: [PATCH 060/284] Proper error messages from lexer errors (e.g. bad characters). --- c/lexer.l | 5 ++++- c/parser.y | 36 ++++++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/c/lexer.l b/c/lexer.l index bb7f57d6..5ceb3a0a 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -15,6 +15,7 @@ %option reentrant %option extra-type="int" %option bison-bridge bison-locations +%option prefix="jq_yy" %% @@ -33,7 +34,7 @@ "//" { return DEFINEDOR; } "."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"-"|"*"|"/"|"\$" { return yytext[0];} -\"(\\.|[^\\"])*\" | +\"(\\.|[^\\\"])*\" | -?[0-9.]+([eE][+-]?[0-9]+)? { yylval->literal = jv_parse_sized(yytext, yyleng); return LITERAL; } @@ -42,6 +43,8 @@ [ \n\t]+ {} +. { return INVALID_CHARACTER; } + %% /* perhaps these should be calls... */ /* diff --git a/c/parser.y b/c/parser.y index 11b88a7f..3d81ea4a 100644 --- a/c/parser.y +++ b/c/parser.y @@ -34,8 +34,13 @@ %parse-param {int* errors} %parse-param {struct locfile* locations} %parse-param {yyscan_t lexer} +%lex-param {block* answer} +%lex-param {int* errors} +%lex-param {struct locfile* locations} %lex-param {yyscan_t lexer} + +%token INVALID_CHARACTER %token IDENT %token LITERAL %token EQ "==" @@ -83,6 +88,29 @@ void yyerror(YYLTYPE* loc, block* answer, int* errors, locfile_locate(locations, *loc); } +int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, block* answer, int* errors, + struct locfile* locations, yyscan_t lexer) { + while (1) { + int tok = jq_yylex(yylval, yylloc, lexer); + if (tok == INVALID_CHARACTER) { + FAIL(*yylloc, "Invalid character"); + } else { + if (tok == LITERAL && !jv_is_valid(yylval->literal)) { + jv msg = jv_invalid_get_msg(jv_copy(yylval->literal)); + if (jv_get_kind(msg) == JV_KIND_STRING) { + FAIL(*yylloc, jv_string_value(msg)); + } else { + FAIL(*yylloc, "Invalid literal"); + } + jv_free(msg); + jv_free(yylval->literal); + yylval->literal = jv_null(); + } + return tok; + } + } +} + static block gen_dictpair(block k, block v) { block b = gen_subexp(k); block_append(&b, gen_subexp(v)); @@ -309,16 +337,16 @@ MkDictPair int compile(const char* str, block* answer) { yyscan_t scanner; YY_BUFFER_STATE buf; - yylex_init_extra(0, &scanner); - buf = yy_scan_string(str, scanner); + jq_yylex_init_extra(0, &scanner); + buf = jq_yy_scan_string(str, scanner); int errors = 0; struct locfile locations; locfile_init(&locations, str, strlen(str)); *answer = gen_noop(); yyparse(answer, &errors, &locations, scanner); locfile_free(&locations); - yy_delete_buffer(buf, scanner); - yylex_destroy(scanner); + jq_yy_delete_buffer(buf, scanner); + jq_yylex_destroy(scanner); if (errors > 0) { block_free(*answer); *answer = gen_noop(); From 0ce437ea9743fc443704181cf785c10b771b8f07 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 11 Sep 2012 10:12:25 +0100 Subject: [PATCH 061/284] More error handling in the parser. Add a special case in the lexer to detect unterminated strings. Add some error recovery in the parser for more copious error spam. --- c/lexer.l | 6 ++++++ c/parser.y | 22 +++++++++++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/c/lexer.l b/c/lexer.l index 5ceb3a0a..9c20a953 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -39,6 +39,12 @@ yylval->literal = jv_parse_sized(yytext, yyleng); return LITERAL; } +\"(\\.|[^\\\"])* { + yylval->literal = jv_invalid_with_msg(jv_string("Unterminated string")); + return LITERAL; +} + + [[:alnum:]]+ { yylval->literal = jv_string(yytext); return IDENT;} [ \n\t]+ {} diff --git a/c/parser.y b/c/parser.y index 3d81ea4a..111d8ee7 100644 --- a/c/parser.y +++ b/c/parser.y @@ -3,7 +3,6 @@ #include #include "compile.h" %} - %code requires { #include "locfile.h" #define YYLTYPE location @@ -170,6 +169,10 @@ Term "as" '$' IDENT '|' Exp { "if" Exp "then" Exp ElseBody { $$ = gen_cond($2, $4, $5); } | +"if" Exp error { + FAIL(@$, "Possibly unterminated 'if' statment"); + $$ = $2; +} | Exp '=' Exp { block assign = gen_op_simple(DUP); @@ -188,7 +191,6 @@ Exp "and" Exp { $$ = gen_and($1, $3); } | - "not" Exp { $$ = gen_not($2); } | @@ -236,6 +238,8 @@ Term { $$ = $1; } + + ElseBody: "elif" Exp "then" Exp ElseBody { $$ = gen_cond($2, $4, $5); @@ -304,16 +308,19 @@ IDENT '(' Exp ')' { block_join($3, gen_op_simple(RET))), gen_noop(), OP_IS_CALL_PSEUDO))); jv_free($1); -} +} | +'(' error ')' { $$ = gen_noop(); } | +'[' error ']' { $$ = gen_noop(); } | +Term '[' error ']' { $$ = $1; } | +'{' error '}' { $$ = gen_noop(); } MkDict: { $$=gen_noop(); -} -| -MkDictPair -{ $$ = $1; } +} | + MkDictPair { $$ = $1; } | MkDictPair ',' MkDict { $$=block_join($1, $3); } +| error ',' MkDict { $$ = $3; } MkDictPair : IDENT ':' ExpD { @@ -332,6 +339,7 @@ MkDictPair | '(' Exp ')' ':' ExpD { $$ = gen_dictpair($2, $5); } +| '(' error ')' ':' ExpD { $$ = $5; } %% int compile(const char* str, block* answer) { From 4c7bede5a46ef25b3d8d06c851d145804f60e20a Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 11 Sep 2012 10:37:44 +0100 Subject: [PATCH 062/284] Better error handling and messages for invalid index/assign operations. --- c/execute.c | 34 ++++++++++++++++++++-------------- c/jv.c | 2 +- c/jv.h | 48 +++++++++++++++++++++--------------------------- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/c/execute.c b/c/execute.c index 9f7b63b5..cbde413a 100644 --- a/c/execute.c +++ b/c/execute.c @@ -133,7 +133,14 @@ static struct closure make_closure(struct forkable_stack* stk, frame_ptr fr, uin } } - +void print_error(jv value) { + assert(!jv_is_valid(value)); + jv msg = jv_invalid_get_msg(value); + if (jv_get_kind(msg) == JV_KIND_STRING) { + fprintf(stderr, "jq: error: %s\n", jv_string_value(msg)); + } + jv_free(msg); +} #define ON_BACKTRACK(op) ((op)+NUM_OPCODES) jv jq_next() { @@ -273,7 +280,13 @@ jv jq_next() { uint16_t v = *pc++; frame_ptr fp = frame_get_level(&frame_stk, frame_current(&frame_stk), level); jv* var = frame_local_var(fp, v); - *var = jv_insert(*var, replacement.value, pathbuf + path_start.pathidx, path_end.pathidx - path_start.pathidx); + jv result = jv_insert(*var, replacement.value, pathbuf + path_start.pathidx, path_end.pathidx - path_start.pathidx); + if (jv_is_valid(result)) { + *var = result; + } else { + print_error(result); + *var = jv_null(); + } break; } @@ -282,13 +295,14 @@ jv jq_next() { jv k = stack_pop().value; int pathidx = path_push(t, jv_copy(k)); jv v = jv_lookup(t.value, k); - if (1 /* fixme invalid lookups */) { + if (jv_is_valid(v)) { stackval sv; sv.value = v; sv.pathidx = pathidx; stack_push(sv); } else { - assert(0 && "bad lookup"); + print_error(v); + goto do_backtrack; } break; } @@ -379,11 +393,7 @@ jv jq_next() { if (jv_is_valid(top.value)) { stack_push(top); } else { - jv msg = jv_invalid_get_msg(top.value); - if (jv_get_kind(msg) == JV_KIND_STRING) { - fprintf(stderr, "jq: error: %s\n", jv_string_value(msg)); - } - jv_free(msg); + print_error(top.value); goto do_backtrack; } break; @@ -405,11 +415,7 @@ jv jq_next() { if (jv_is_valid(top.value)) { stack_push(top); } else { - jv msg = jv_invalid_get_msg(top.value); - if (jv_get_kind(msg) == JV_KIND_STRING) { - fprintf(stderr, "jq: error: %s\n", jv_string_value(msg)); - } - jv_free(msg); + print_error(top.value); goto do_backtrack; } break; diff --git a/c/jv.c b/c/jv.c index f8b79ce6..214354ce 100644 --- a/c/jv.c +++ b/c/jv.c @@ -49,7 +49,7 @@ const char* jv_kind_name(jv_kind k) { case JV_KIND_ARRAY: return "array"; case JV_KIND_OBJECT: return "object"; } - assert(0); + assert(0 && "invalid kind"); return ""; } diff --git a/c/jv.h b/c/jv.h index ef64816c..3c557c45 100644 --- a/c/jv.h +++ b/c/jv.h @@ -126,39 +126,33 @@ static jv jv_lookup(jv t, jv k) { jv_free(k); v = jv_null(); } else { - assert(0&&"bad lookup"); + v = jv_invalid_with_msg(jv_string_fmt("Cannot index %s with %s", + jv_kind_name(jv_get_kind(t)), + jv_kind_name(jv_get_kind(k)))); + jv_free(t); + jv_free(k); } return v; - // FIXME: invalid indexes, JV_KIND_INVALID - /* - if (v) - return v; - else - return jv_null(); - */ } static jv jv_modify(jv t, jv k, jv v) { - if (jv_get_kind(k) == JV_KIND_STRING) { - if (jv_get_kind(t) == JV_KIND_NULL) { - t = jv_object(); - } - if (jv_get_kind(t) == JV_KIND_OBJECT) { - t = jv_object_set(t, k, v); - } else { - assert(0 && "bad mod - not an object"); - } - } else if (jv_get_kind(k) == JV_KIND_NUMBER) { - if (jv_get_kind(t) == JV_KIND_NULL) { - t = jv_array(); - } - if (jv_get_kind(t) == JV_KIND_ARRAY) { - t = jv_array_set(t, (int)jv_number_value(k), v); - } else { - assert(0 && "bad mod - not an array"); - } + int isnull = jv_get_kind(t) == JV_KIND_NULL; + if (jv_get_kind(k) == JV_KIND_STRING && + (jv_get_kind(t) == JV_KIND_OBJECT || isnull)) { + if (isnull) t = jv_object(); + t = jv_object_set(t, k, v); + } else if (jv_get_kind(k) == JV_KIND_NUMBER && + (jv_get_kind(t) == JV_KIND_ARRAY || isnull)) { + if (isnull) t = jv_array(); + t = jv_array_set(t, (int)jv_number_value(k), v); } else { - assert(0 && "bad mod - seriously, wtf"); + jv err = jv_invalid_with_msg(jv_string_fmt("Cannot update field at %s index of %s", + jv_kind_name(jv_get_kind(t)), + jv_kind_name(jv_get_kind(v)))); + jv_free(t); + jv_free(k); + jv_free(v); + t = err; } return t; } From 062a6aa6d7b9c8ead18cc9cbbe0f458a7e2b7db9 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 11 Sep 2012 12:24:54 +0100 Subject: [PATCH 063/284] More error handling - locations of refs to undefined symbols. --- c/compile.c | 40 ++++++++++++++++++++++++++++++++-------- c/compile.h | 5 ++++- c/locfile.h | 26 +++++++++++++++++++++----- c/main.c | 45 ++++++++++++++++++++++++++------------------- c/parser.y | 17 +++++++---------- 5 files changed, 90 insertions(+), 43 deletions(-) diff --git a/c/compile.c b/c/compile.c index b7f91aa3..c45d45a1 100644 --- a/c/compile.c +++ b/c/compile.c @@ -3,7 +3,7 @@ #include #include "opcode.h" #include "compile.h" - +#include "locfile.h" struct inst { struct inst* next; @@ -18,6 +18,8 @@ struct inst { struct cfunction* cfunc; } imm; + location source; + // Binding // An instruction requiring binding (for parameters/variables) // is in one of three states: @@ -45,6 +47,7 @@ static inst* inst_new(opcode op) { i->bound_by = 0; i->symbol = 0; i->subfn = gen_noop(); + i->source = UNKNOWN_LOCATION; return i; } @@ -82,6 +85,16 @@ static inst* block_take(block* b) { return i; } +block gen_location(location loc, block b) { + for (inst* i = b.first; i; i = i->next) { + if (i->source.start == UNKNOWN_LOCATION.start && + i->source.end == UNKNOWN_LOCATION.end) { + i->source = loc; + } + } + return b; +} + block gen_noop() { block b = {0,0}; return b; @@ -429,7 +442,8 @@ static int count_cfunctions(block b) { return n; } -static void compile(struct bytecode* bc, block b) { +static int compile(struct locfile* locations, struct bytecode* bc, block b) { + int errors = 0; int pos = 0; int var_frame_idx = 0; bc->nsubfunctions = 0; @@ -442,7 +456,10 @@ static void compile(struct bytecode* bc, block b) { int opflags = opcode_describe(curr->op)->flags; if (opflags & OP_HAS_BINDING) { - assert(curr->bound_by && "unbound term"); + if (!curr->bound_by) { + locfile_locate(locations, curr->source, "error: %s is not defined", curr->symbol); + errors++; + } } if ((opflags & OP_HAS_VARIABLE) && curr->bound_by == curr) { @@ -472,7 +489,7 @@ static void compile(struct bytecode* bc, block b) { bc->subfunctions[curr->imm.intval] = subfn; subfn->globals = bc->globals; subfn->parent = bc; - compile(subfn, curr->subfn); + errors += compile(locations, subfn, curr->subfn); } } else { bc->subfunctions = 0; @@ -483,7 +500,7 @@ static void compile(struct bytecode* bc, block b) { pos = 0; jv constant_pool = jv_array(); int maxvar = -1; - for (inst* curr = b.first; curr; curr = curr->next) { + if (!errors) for (inst* curr = b.first; curr; curr = curr->next) { const struct opcode_description* op = opcode_describe(curr->op); if (op->length == 0) continue; @@ -551,18 +568,25 @@ static void compile(struct bytecode* bc, block b) { } bc->constants = constant_pool; bc->nlocals = maxvar + 2; // FIXME: frames of size zero? + return errors; } -struct bytecode* block_compile(block b) { +int block_compile(block b, struct locfile* locations, struct bytecode** out) { struct bytecode* bc = malloc(sizeof(struct bytecode)); bc->parent = 0; bc->globals = malloc(sizeof(struct symbol_table)); int ncfunc = count_cfunctions(b); bc->globals->ncfunctions = 0; bc->globals->cfunctions = malloc(sizeof(struct cfunction) * ncfunc); - compile(bc, b); + int nerrors = compile(locations, bc, b); assert(bc->globals->ncfunctions == ncfunc); - return bc; + if (nerrors > 0) { + bytecode_free(bc); + *out = 0; + } else { + *out = bc; + } + return nerrors; } void block_free(block b) { diff --git a/c/compile.h b/c/compile.h index 8f9526b0..bdaf6a88 100644 --- a/c/compile.h +++ b/c/compile.h @@ -1,6 +1,7 @@ #include #include "bytecode.h" #include "opcode.h" +#include "locfile.h" struct inst; typedef struct inst inst; @@ -11,6 +12,8 @@ typedef struct block { inst* last; } block; +block gen_location(location, block); + block gen_noop(); block gen_op_simple(opcode op); block gen_op_const(opcode op, jv constant); @@ -39,7 +42,7 @@ void block_append(block* b, block b2); block block_join(block a, block b); block block_bind(block binder, block body, int bindflags); -struct bytecode* block_compile(block); +int block_compile(block, struct locfile*, struct bytecode**); void block_free(block); diff --git a/c/locfile.h b/c/locfile.h index 0f605bbb..77b1aef1 100644 --- a/c/locfile.h +++ b/c/locfile.h @@ -1,10 +1,15 @@ +#ifndef _LOCFILE_H +#define _LOCFILE_H #include #include #include +#include typedef struct { int start, end; } location; +static const location UNKNOWN_LOCATION = {-1, -1}; + struct locfile { const char* data; int length; @@ -48,15 +53,26 @@ static int locfile_line_length(struct locfile* l, int line) { return l->linemap[line+1] - l->linemap[line]; } -static void locfile_locate(struct locfile* l, location loc) { +static void locfile_locate(struct locfile* l, location loc, const char* fmt, ...) { + va_list fmtargs; + va_start(fmtargs, fmt); + vfprintf(stderr, fmt, fmtargs); + va_end(fmtargs); + fprintf(stderr, "\n"); + if (loc.start == -1) { + fprintf(stderr, "\n"); + return; + } int startline = locfile_get_line(l, loc.start); int offset = l->linemap[startline]; - printf("%.*s\n", locfile_line_length(l, startline), l->data + offset); - printf("%*s", loc.start - offset, ""); + fprintf(stderr, "%.*s\n", locfile_line_length(l, startline), l->data + offset); + fprintf(stderr, "%*s", loc.start - offset, ""); for (int i = loc.start; i < loc.end && i < offset + locfile_line_length(l, startline); i++){ - printf("^"); + fprintf(stderr, "^"); } - printf("\n"); + fprintf(stderr, "\n"); } + +#endif diff --git a/c/main.c b/c/main.c index 4faf2a0b..f6d9e67f 100644 --- a/c/main.c +++ b/c/main.c @@ -1,15 +1,36 @@ #include +#include #include "compile.h" #include "parser.tab.h" #include "builtin.h" #include "jv.h" +#include "locfile.h" -int compile(const char* str, block* answer); +int jq_parse(struct locfile* source, block* answer); void jq_init(struct bytecode* bc, jv value); jv jq_next(); void jq_teardown(); +struct bytecode* jq_compile(const char* str) { + struct locfile locations; + locfile_init(&locations, str, strlen(str)); + block program; + struct bytecode* bc = 0; + int nerrors = jq_parse(&locations, &program); + if (nerrors == 0) { + block_append(&program, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK))); + program = gen_cbinding(&builtins, program); + nerrors = block_compile(program, &locations, &bc); + block_free(program); + } + if (nerrors) { + fprintf(stderr, "%d compile %s\n", nerrors, nerrors > 1 ? "errors" : "error"); + } + locfile_free(&locations); + return bc; +} + void run_program(struct bytecode* bc) { #if JQ_DEBUG @@ -52,14 +73,8 @@ void run_tests() { if (skipline(buf)) continue; printf("Testing %s\n", buf); int pass = 1; - block program; - int nerrors = compile(buf, &program); - assert(nerrors == 0); - block_append(&program, gen_op_simple(YIELD)); - block_append(&program, gen_op_simple(BACKTRACK)); - program = gen_cbinding(&builtins, program); - struct bytecode* bc = block_compile(program); - block_free(program); + struct bytecode* bc = jq_compile(buf); + assert(bc); printf("Disassembly:\n"); dump_disassembly(2, bc); printf("\n"); @@ -111,16 +126,8 @@ void run_tests() { int main(int argc, char* argv[]) { if (argc == 1) { run_tests(); return 0; } - block blk; - int nerrors = compile(argv[1], &blk); - if (nerrors > 0) { - printf("%d compile %s\n", nerrors, nerrors > 1 ? "errors" : "error"); - return 1; - } - block_append(&blk, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK))); - blk = gen_cbinding(&builtins, blk); - struct bytecode* bc = block_compile(blk); - block_free(blk); + struct bytecode* bc = jq_compile(argv[1]); + if (!bc) return 1; run_program(bc); bytecode_free(bc); return 0; diff --git a/c/parser.y b/c/parser.y index 111d8ee7..70fb7116 100644 --- a/c/parser.y +++ b/c/parser.y @@ -83,8 +83,7 @@ void yyerror(YYLTYPE* loc, block* answer, int* errors, struct locfile* locations, yyscan_t lexer, const char *s){ (*errors)++; - printf("error: %s\n", s); - locfile_locate(locations, *loc); + locfile_locate(locations, *loc, "error: %s", s); } int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, block* answer, int* errors, @@ -293,11 +292,11 @@ LITERAL { block_append(&$$, gen_op_simple(POP)); } | '$' IDENT { - $$ = gen_op_var_unbound(LOADV, jv_string_value($2)); + $$ = gen_location(@$, gen_op_var_unbound(LOADV, jv_string_value($2))); jv_free($2); } | IDENT { - $$ = gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, jv_string_value($1))); + $$ = gen_location(@$, gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, jv_string_value($1)))); jv_free($1); } | IDENT '(' Exp ')' { @@ -307,6 +306,7 @@ IDENT '(' Exp ')' { "lambda", block_join($3, gen_op_simple(RET))), gen_noop(), OP_IS_CALL_PSEUDO))); + $$ = gen_location(@1, $$); jv_free($1); } | '(' error ')' { $$ = gen_noop(); } | @@ -342,17 +342,14 @@ MkDictPair | '(' error ')' ':' ExpD { $$ = $5; } %% -int compile(const char* str, block* answer) { +int jq_parse(struct locfile* locations, block* answer) { yyscan_t scanner; YY_BUFFER_STATE buf; jq_yylex_init_extra(0, &scanner); - buf = jq_yy_scan_string(str, scanner); + buf = jq_yy_scan_bytes(locations->data, locations->length, scanner); int errors = 0; - struct locfile locations; - locfile_init(&locations, str, strlen(str)); *answer = gen_noop(); - yyparse(answer, &errors, &locations, scanner); - locfile_free(&locations); + yyparse(answer, &errors, locations, scanner); jq_yy_delete_buffer(buf, scanner); jq_yylex_destroy(scanner); if (errors > 0) { From 51a44edc63bf4f1749458faf5ae631e0d5023ba9 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 11 Sep 2012 14:52:10 +0100 Subject: [PATCH 064/284] JSON stream parser. Allow multiple values on input as concatenated JSON objects, possibly separated by whitespace. --- c/jv.c | 7 ++++ c/jv.h | 2 + c/jv_dtoa.h | 4 +- c/jv_parse.c | 116 +++++++++++++++++++++++++++++++++++++++------------ c/jv_parse.h | 17 +++++++- c/jv_print.c | 2 +- c/main.c | 61 +++++++++++++++------------ 7 files changed, 153 insertions(+), 56 deletions(-) diff --git a/c/jv.c b/c/jv.c index 214354ce..786e7b26 100644 --- a/c/jv.c +++ b/c/jv.c @@ -103,6 +103,13 @@ jv jv_invalid_get_msg(jv inv) { return x; } +int jv_invalid_has_msg(jv inv) { + jv msg = jv_invalid_get_msg(inv); + int r = jv_get_kind(msg) != JV_KIND_NULL; + jv_free(msg); + return r; +} + static void jvp_invalid_free(jv_complex* x) { if (jvp_refcnt_dec(x)) { jv_free(((jvp_invalid*)x->ptr)->errmsg); diff --git a/c/jv.h b/c/jv.h index 3c557c45..48ae0e0f 100644 --- a/c/jv.h +++ b/c/jv.h @@ -52,6 +52,8 @@ int jv_equal(jv, jv); jv jv_invalid(); jv jv_invalid_with_msg(jv); jv jv_invalid_get_msg(jv); +int jv_invalid_has_msg(jv); + jv jv_null(); jv jv_true(); diff --git a/c/jv_dtoa.h b/c/jv_dtoa.h index e9346c0e..3bafcf47 100644 --- a/c/jv_dtoa.h +++ b/c/jv_dtoa.h @@ -1,4 +1,5 @@ - +#ifndef JV_DTOA_H +#define JV_DTOA_H #define Kmax 7 struct Bigint; @@ -18,3 +19,4 @@ void jvp_freedtoa(struct dtoa_context* C, char *s); #define JVP_DTOA_FMT_MAX_LEN 32 char* jvp_dtoa_fmt(struct dtoa_context* C, register char *b, double x); +#endif diff --git a/c/jv_parse.c b/c/jv_parse.c index 7fd4d2d2..e4565ef7 100644 --- a/c/jv_parse.c +++ b/c/jv_parse.c @@ -22,11 +22,15 @@ void jv_parser_init(struct jv_parser* p) { p->tokenbuf = 0; p->tokenlen = p->tokenpos = 0; p->st = JV_PARSER_NORMAL; + p->curr_buf = 0; + p->curr_buf_length = p->curr_buf_pos = p->curr_buf_is_partial = 0; jvp_dtoa_context_init(&p->dtoa); } void jv_parser_free(struct jv_parser* p) { jv_free(p->next); + for (int i=0; istackpos; i++) + jv_free(p->stack[i]); free(p->stack); free(p->tokenbuf); jvp_dtoa_context_free(&p->dtoa); @@ -271,13 +275,25 @@ static chclass classify(char c) { } +static presult OK = "output produced"; +static int check_done(struct jv_parser* p, jv* out) { + if (p->stackpos == 0 && jv_is_valid(p->next)) { + *out = p->next; + p->next = jv_invalid(); + return 1; + } else { + return 0; + } +} -static pfunc scan(struct jv_parser* p, char ch) { +static pfunc scan(struct jv_parser* p, char ch, jv* out) { + presult answer = 0; if (p->st == JV_PARSER_NORMAL) { chclass cls = classify(ch); if (cls != LITERAL) { TRY(check_literal(p)); + if (check_done(p, out)) answer = OK; } switch (cls) { case LITERAL: @@ -294,10 +310,12 @@ static pfunc scan(struct jv_parser* p, char ch) { case INVALID: return "Invalid character"; } + if (check_done(p, out)) answer = OK; } else { if (ch == '"' && p->st == JV_PARSER_STRING) { TRY(found_string(p)); p->st = JV_PARSER_NORMAL; + if (check_done(p, out)) answer = OK; } else { tokenadd(p, ch); if (ch == '\\' && p->st == JV_PARSER_STRING) { @@ -307,43 +325,87 @@ static pfunc scan(struct jv_parser* p, char ch) { } } } - return 0; + return answer; } -static pfunc finish(struct jv_parser* p) { - if (p->st != JV_PARSER_NORMAL) - return "Unfinished string"; - TRY(check_literal(p)); +void jv_parser_set_buf(struct jv_parser* p, const char* buf, int length, int is_partial) { + assert((p->curr_buf == 0 || p->curr_buf_pos == p->curr_buf_length) + && "previous buffer not exhausted"); + p->curr_buf = buf; + p->curr_buf_length = length; + p->curr_buf_pos = 0; + p->curr_buf_is_partial = is_partial; +} - if (p->stackpos != 0) - return "Unfinished JSON term"; - - // this will happen on the empty string - if (!jv_is_valid(p->next)) - return "Expected JSON value"; - - return 0; +jv jv_parser_next(struct jv_parser* p) { + assert(p->curr_buf && "a buffer must be provided"); + jv value; + presult msg = 0; + while (!msg && p->curr_buf_pos < p->curr_buf_length) { + char ch = p->curr_buf[p->curr_buf_pos++]; + msg = scan(p, ch, &value); + } + if (msg == OK) { + return value; + } else if (msg) { + return jv_invalid_with_msg(jv_string(msg)); + } else if (p->curr_buf_is_partial) { + assert(p->curr_buf_pos == p->curr_buf_length); + // need another buffer + return jv_invalid(); + } else { + assert(p->curr_buf_pos == p->curr_buf_length); + // at EOF + if (p->st != JV_PARSER_NORMAL) + return jv_invalid_with_msg(jv_string("Unfinished string")); + if ((msg = check_literal(p))) + return jv_invalid_with_msg(jv_string(msg)); + if (p->stackpos != 0) + return jv_invalid_with_msg(jv_string("Unfinished JSON term")); + // p->next is either invalid (nothing here but no syntax error) + // or valid (this is the value). either way it's the thing to return + value = p->next; + p->next = jv_invalid(); + return value; + } } jv jv_parse_sized(const char* string, int length) { struct jv_parser parser; jv_parser_init(&parser); - - const char* p = string; - char ch; - presult msg = 0; - while (msg == 0 && p < string + length) { - ch = *p++; - msg = scan(&parser, ch); - } - if (msg == 0) msg = finish(&parser); - jv value; - if (msg) { - value = jv_invalid_with_msg(jv_string_fmt("%s (while parsing '%s')", msg, string)); + jv_parser_set_buf(&parser, string, length, 0); + jv value = jv_parser_next(&parser); + if (jv_is_valid(value)) { + jv next = jv_parser_next(&parser); + if (jv_is_valid(next)) { + // multiple JSON values, we only wanted one + jv_free(value); + jv_free(next); + value = jv_invalid_with_msg(jv_string("Unexpected extra JSON values")); + } else if (jv_invalid_has_msg(jv_copy(next))) { + // parser error after the first JSON value + jv_free(value); + value = next; + } else { + // a single valid JSON value + jv_free(next); + } + } else if (jv_invalid_has_msg(jv_copy(value))) { + // parse error, we'll return it } else { - value = jv_copy(parser.next); + // no value at all + jv_free(value); + value = jv_invalid_with_msg(jv_string("Expected JSON value")); } jv_parser_free(&parser); + + if (!jv_is_valid(value) && jv_invalid_has_msg(jv_copy(value))) { + jv msg = jv_invalid_get_msg(value); + value = jv_invalid_with_msg(jv_string_fmt("%s (while parsing '%s')", + jv_string_value(msg), + string)); + jv_free(msg); + } return value; } diff --git a/c/jv_parse.h b/c/jv_parse.h index 10270766..5b8e7cdf 100644 --- a/c/jv_parse.h +++ b/c/jv_parse.h @@ -1,5 +1,12 @@ - +#ifndef JV_PARSE_H +#define JV_PARSE_H +#include "jv_dtoa.h" struct jv_parser { + const char* curr_buf; + int curr_buf_length; + int curr_buf_pos; + int curr_buf_is_partial; + jv* stack; int stackpos; int stacklen; @@ -17,3 +24,11 @@ struct jv_parser { JV_PARSER_STRING_ESCAPE } st; }; + +void jv_parser_init(struct jv_parser* p); +void jv_parser_free(struct jv_parser* p); + +void jv_parser_set_buf(struct jv_parser* p, const char* buf, int length, int is_partial); + +jv jv_parser_next(struct jv_parser* p); +#endif diff --git a/c/jv_print.c b/c/jv_print.c index c2f7f58d..e122a5c8 100644 --- a/c/jv_print.c +++ b/c/jv_print.c @@ -10,7 +10,7 @@ static void jv_dump_string(jv str, int ascii_only) { assert(jv_get_kind(str) == JV_KIND_STRING); const char* i = jv_string_value(str); const char* end = i + jv_string_length(jv_copy(str)); - int c; + int c = 0; while ((i = jvp_utf8_next(i, end, &c))) { assert(c != -1); int unicode_escape = 0; diff --git a/c/main.c b/c/main.c index f6d9e67f..05288d1b 100644 --- a/c/main.c +++ b/c/main.c @@ -4,6 +4,7 @@ #include "parser.tab.h" #include "builtin.h" #include "jv.h" +#include "jv_parse.h" #include "locfile.h" int jq_parse(struct locfile* source, block* answer); @@ -31,31 +32,6 @@ struct bytecode* jq_compile(const char* str) { return bc; } - -void run_program(struct bytecode* bc) { -#if JQ_DEBUG - dump_disassembly(0, bc); - printf("\n"); -#endif - char buf[409600]; - fgets(buf, sizeof(buf), stdin); - jv value = jv_parse(buf); - if (!jv_is_valid(value)) { - assert(0 && "couldn't parse input"); //FIXME - } - jq_init(bc, value); - jv result; - while (jv_is_valid(result = jq_next())) { - jv_dump(result); - printf("\n"); - } - jv_free(result); - #if JQ_DEBUG - printf("end of results\n"); - #endif - jq_teardown(); -} - int skipline(const char* buf) { int p = 0; while (buf[p] == ' ' || buf[p] == '\t') p++; @@ -128,7 +104,40 @@ int main(int argc, char* argv[]) { if (argc == 1) { run_tests(); return 0; } struct bytecode* bc = jq_compile(argv[1]); if (!bc) return 1; - run_program(bc); + +#if JQ_DEBUG + dump_disassembly(0, bc); + printf("\n"); +#endif + + struct jv_parser parser; + jv_parser_init(&parser); + while (!feof(stdin)) { + char buf[4096]; + if (!fgets(buf, sizeof(buf), stdin)) buf[0] = 0; + jv_parser_set_buf(&parser, buf, strlen(buf), !feof(stdin)); + jv value; + while (jv_is_valid((value = jv_parser_next(&parser)))) { + jq_init(bc, value); + jv result; + while (jv_is_valid(result = jq_next())) { + jv_dump(result); + printf("\n"); + } + jv_free(result); + jq_teardown(); + } + if (jv_invalid_has_msg(jv_copy(value))) { + jv msg = jv_invalid_get_msg(value); + fprintf(stderr, "parse error: %s\n", jv_string_value(msg)); + jv_free(msg); + break; + } else { + jv_free(value); + } + } + jv_parser_free(&parser); + bytecode_free(bc); return 0; } From d9d6f434079f842674becdea31521f54655d5bdd Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 11 Sep 2012 15:51:12 +0100 Subject: [PATCH 065/284] Pretty-printing of JSON values. --- c/bytecode.c | 2 +- c/jv.h | 4 +++- c/jv_print.c | 50 +++++++++++++++++++++++++++++++++++--------------- c/main.c | 8 ++++---- 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/c/bytecode.c b/c/bytecode.c index 208e82f0..bafd0474 100644 --- a/c/bytecode.c +++ b/c/bytecode.c @@ -58,7 +58,7 @@ void dump_operation(struct bytecode* bc, uint16_t* codeptr) { printf(" %04d", pc + imm); } else if (op->flags & OP_HAS_CONSTANT) { printf(" "); - jv_dump(jv_array_get(jv_copy(bc->constants), imm)); + jv_dump(jv_array_get(jv_copy(bc->constants), imm), 0); } else if (op->flags & OP_HAS_VARIABLE) { uint16_t v = bc->code[pc++]; printf(" v%d", v); diff --git a/c/jv.h b/c/jv.h index 48ae0e0f..ec23262c 100644 --- a/c/jv.h +++ b/c/jv.h @@ -102,7 +102,9 @@ jv jv_object_iter_value(jv, int); int jv_get_refcnt(jv); -void jv_dump(jv); +enum { JV_PRINT_PRETTY = 1, JV_PRINT_ASCII = 2 }; +void jv_dump(jv, int); + jv jv_parse(const char* string); jv jv_parse_sized(const char* string, int length); diff --git a/c/jv_print.c b/c/jv_print.c index e122a5c8..f1ec92fb 100644 --- a/c/jv_print.c +++ b/c/jv_print.c @@ -64,7 +64,9 @@ static void jv_dump_string(jv str, int ascii_only) { assert(c != -1); } -static void jv_dump_term(struct dtoa_context* C, jv x) { +enum { INDENT = 2 }; + +static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent) { char buf[JVP_DTOA_FMT_MAX_LEN]; switch (jv_get_kind(x)) { case JV_KIND_INVALID: @@ -99,33 +101,51 @@ static void jv_dump_term(struct dtoa_context* C, jv x) { putchar('"'); break; case JV_KIND_ARRAY: { - printf("["); - for (int i=0; i Date: Tue, 11 Sep 2012 16:10:55 +0100 Subject: [PATCH 066/284] Make .[] capable of iteration over objects as well as arrays. Also change an assert to a proper error message if it's given something silly like a number. --- c/execute.c | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/c/execute.c b/c/execute.c index cbde413a..8426d3ca 100644 --- a/c/execute.c +++ b/c/execute.c @@ -326,25 +326,51 @@ jv jq_next() { } case EACH: - stack_push(stackval_root(jv_number(0))); + stack_push(stackval_root(jv_number(-1))); // fallthrough case ON_BACKTRACK(EACH): { int idx = jv_number_value(stack_pop().value); - stackval array = stack_pop(); - if (idx >= jv_array_length(jv_copy(array.value))) { - jv_free(array.value); + stackval container = stack_pop(); + + int is_array, keep_going; + jv key, value; + if (jv_get_kind(container.value) == JV_KIND_ARRAY) { + is_array = 1; + if (opcode == EACH) idx = 0; + else idx = idx + 1; + keep_going = idx < jv_array_length(jv_copy(container.value)); + if (keep_going) { + key = jv_number(idx); + value = jv_array_get(jv_copy(container.value), idx); + } + } else if (jv_get_kind(container.value) == JV_KIND_OBJECT) { + is_array = 0; + if (opcode == EACH) idx = jv_object_iter(container.value); + else idx = jv_object_iter_next(container.value, idx); + keep_going = jv_object_iter_valid(container.value, idx); + if (keep_going) { + key = jv_object_iter_key(container.value, idx); + value = jv_object_iter_value(container.value, idx); + } + } else { + assert(opcode == EACH); + print_error(jv_invalid_with_msg(jv_string_fmt("Cannot iterate over %s", + jv_kind_name(jv_get_kind(container.value))))); + keep_going = 0; + } + + if (!keep_going) { + jv_free(container.value); goto do_backtrack; } else { stack_save(); - stackval array2 = array; - array2.value = jv_copy(array2.value); - stack_push(array2); - stack_push(stackval_root(jv_number(idx+1))); + stack_push(container); + stack_push(stackval_root(jv_number(idx))); frame_push_backtrack(&frame_stk, pc - 1); stack_switch(); - stackval sv = {jv_array_get(array.value, idx), - path_push(array, jv_number(idx))}; + stackval sv = {value, + path_push(container, key)}; stack_push(sv); } break; From df195b31873010f18883446c6e0e629a594badc5 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 11 Sep 2012 23:55:59 +0100 Subject: [PATCH 067/284] Add update operators (+=, -=, *=, /= and //=) --- c/lexer.l | 7 ++++++- c/parser.y | 45 ++++++++++++++++++++++++++++++++++++++------- c/testdata | 11 +++++++++++ 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/c/lexer.l b/c/lexer.l index 9c20a953..dd93f497 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -22,7 +22,6 @@ "==" { return EQ; } "as" { return AS; } "def" { return DEF; } -"|=" { return SETPIPE; } "if" { return IF; } "then" { return THEN; } "else" { return ELSE; } @@ -32,6 +31,12 @@ "not" { return NOT; } "end" { return END; } "//" { return DEFINEDOR; } +"|=" { return SETPIPE; } +"+=" { return SETPLUS; } +"-=" { return SETMINUS; } +"*=" { return SETMULT; } +"/=" { return SETDIV; } +"//=" { return SETDEFINEDOR; } "."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"-"|"*"|"/"|"\$" { return yytext[0];} \"(\\.|[^\\\"])*\" | diff --git a/c/parser.y b/c/parser.y index 70fb7116..d8780a87 100644 --- a/c/parser.y +++ b/c/parser.y @@ -46,7 +46,6 @@ %token DEFINEDOR "//" %token AS "as" %token DEF "def" -%token SETPIPE "|=" %token IF "if" %token THEN "then" %token ELSE "else" @@ -55,14 +54,19 @@ %token AND "and" %token OR "or" %token NOT "not" - +%token SETPIPE "|=" +%token SETPLUS "+=" +%token SETMINUS "-=" +%token SETMULT "*=" +%token SETDIV "/=" +%token SETDEFINEDOR "//=" /* revolting hack */ %left ';' %left '|' %left ',' %right "//" -%nonassoc '=' SETPIPE +%nonassoc '=' SETPIPE SETPLUS SETMINUS SETMULT SETDIV SETDEFINEDOR %nonassoc EQ %left OR %left AND @@ -138,6 +142,16 @@ static block gen_binop(block a, block b, int op) { return c; } +static block gen_update(block a, block op, int optype) { + block assign = a; + block_append(&assign, gen_op_simple(DUP)); + if (optype) { + op = gen_binop(gen_noop(), op, optype); + } + block_append(&assign, op); + return gen_assign(assign); +} + %} %% @@ -198,11 +212,12 @@ Exp "//" Exp { $$ = gen_definedor($1, $3); } | +Exp "//=" Exp { + $$ = gen_update($1, gen_definedor(gen_noop(), $3), 0); +} | + Exp "|=" Exp { - block assign = $1; - block_append(&assign, gen_op_simple(DUP)); - block_append(&assign, $3); - $$ = gen_assign(assign); + $$ = gen_update($1, $3, 0); } | Exp '|' Exp { @@ -217,18 +232,34 @@ Exp '+' Exp { $$ = gen_binop($1, $3, '+'); } | +Exp "+=" Exp { + $$ = gen_update($1, $3, '+'); +} | + Exp '-' Exp { $$ = gen_binop($1, $3, '-'); } | +Exp "-=" Exp { + $$ = gen_update($1, $3, '-'); +} | + Exp '*' Exp { $$ = gen_binop($1, $3, '*'); } | +Exp "*=" Exp { + $$ = gen_update($1, $3, '*'); +} | + Exp '/' Exp { $$ = gen_binop($1, $3, '/'); } | +Exp "/=" Exp { + $$ = gen_update($1, $3, '/'); +} | + Exp "==" Exp { $$ = gen_binop($1, $3, EQ); } | diff --git a/c/testdata b/c/testdata index bd1d7f25..e17f2bb7 100644 --- a/c/testdata +++ b/c/testdata @@ -270,6 +270,13 @@ def id(x):x; 2000 as $x | def f(x):1 as $x | id([$x, x, x]); def g(x): 100 as $x {"foo": 42} {"foo": 43} +.[] += 2, .[] *= 2, .[] -= 2, .[] /= 2 +[1,3,5] +[3,5,7] +[2,6,10] +[-1,1,3] +[0.5, 1.5, 2.5] + .[0].a |= {"old":., "new":(.+1)} [{"a":1,"b":2}] [{"a":{"old":1, "new":2},"b":2}] @@ -305,6 +312,10 @@ def inc(x): x |= .+1; inc(.[].a) [{"foo":[1,2], "bar": 42}, {"foo":[1], "bar": null}, {"foo":[null,false,3], "bar": 18}, {"foo":[], "bar":42}, {"foo": [null,false,null], "bar": 41}] [[1,2], [1], [3], [42], [41]] +.[] //= 42 +["hello",true,false,[false],null] +["hello",true,42,[false],42] + .[] | [.[0] and .[1], .[0] or .[1]] [[true,[]], [false,1], [42,null], [null,false]] [true,true] From cc2fb20ca03ca0cd30c0d9c768ead9b8cb7130f9 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sun, 16 Sep 2012 11:07:36 +0100 Subject: [PATCH 068/284] Hrm. Update operators (//=, +=, etc.) aren't very well thought out. In complex cases, their behaviour is kinda weird. Here's a failing test for what I think they should do. --- c/testdata | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/c/testdata b/c/testdata index e17f2bb7..a905d2af 100644 --- a/c/testdata +++ b/c/testdata @@ -312,9 +312,10 @@ def inc(x): x |= .+1; inc(.[].a) [{"foo":[1,2], "bar": 42}, {"foo":[1], "bar": null}, {"foo":[null,false,3], "bar": 18}, {"foo":[], "bar":42}, {"foo": [null,false,null], "bar": 41}] [[1,2], [1], [3], [42], [41]] -.[] //= 42 -["hello",true,false,[false],null] -["hello",true,42,[false],42] +# FIXME: behaviour of update operators +# .[] //= .[0] +# ["hello",true,false,[false],null] +# ["hello",true,"hello",[false],"hello"] .[] | [.[0] and .[1], .[0] or .[1]] [[true,[]], [false,1], [42,null], [null,false]] From 539156430aea44c700e40f25557994ecddae6165 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sun, 16 Sep 2012 11:08:42 +0100 Subject: [PATCH 069/284] Builtin function 'length', for arrays/objects/strings. --- c/builtin.c | 15 +++++++++++++++ c/testdata | 3 +++ 2 files changed, 18 insertions(+) diff --git a/c/builtin.c b/c/builtin.c index 375e3252..39d3f24d 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -129,6 +129,20 @@ static void f_tonumber(jv input[], jv output[]) { } } +static void f_length(jv input[], jv output[]) { + if (jv_get_kind(input[0]) == JV_KIND_ARRAY) { + output[0] = jv_number(jv_array_length(input[0])); + } else if (jv_get_kind(input[0]) == JV_KIND_OBJECT) { + output[0] = jv_number(jv_object_length(input[0])); + } else if (jv_get_kind(input[0]) == JV_KIND_STRING) { + output[0] = jv_number(jv_string_length(input[0])); + } else { + output[0] = jv_invalid_with_msg(jv_string_fmt("Cannot get the length of %s", + jv_kind_name(jv_get_kind(input[0])))); + jv_free(input[0]); + } +} + struct cfunction function_list[] = { {f_true, "true", CALL_BUILTIN_1_1}, {f_false, "false", CALL_BUILTIN_1_1}, @@ -139,5 +153,6 @@ struct cfunction function_list[] = { {f_divide, "_divide", CALL_BUILTIN_3_1}, {f_tonumber, "tonumber", CALL_BUILTIN_1_1}, {f_equal, "_equal", CALL_BUILTIN_3_1}, + {f_length, "length", CALL_BUILTIN_1_1}, }; struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; diff --git a/c/testdata b/c/testdata index a905d2af..f2eb32a2 100644 --- a/c/testdata +++ b/c/testdata @@ -203,6 +203,9 @@ null [false, false, false, false, false, false, false, true, false] [false, false, false, false, false, false, false, false, true ] +[.[] | length] +[[], {}, [1,2], {"a":42}, "asdf"] +[0, 0, 2, 1, 4] # # User-defined functions From 50ebb036c4bfff28e6288e69751efbd9e7298f4f Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Sun, 16 Sep 2012 17:08:56 +0100 Subject: [PATCH 070/284] Bind builtin functions in a slightly less ugly way. --- c/builtin.c | 8 ++++++-- c/builtin.h | 3 ++- c/compile.h | 4 ++++ c/main.c | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/c/builtin.c b/c/builtin.c index 39d3f24d..9be18208 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -143,7 +143,7 @@ static void f_length(jv input[], jv output[]) { } } -struct cfunction function_list[] = { +static struct cfunction function_list[] = { {f_true, "true", CALL_BUILTIN_1_1}, {f_false, "false", CALL_BUILTIN_1_1}, {f_null, "null", CALL_BUILTIN_1_1}, @@ -155,4 +155,8 @@ struct cfunction function_list[] = { {f_equal, "_equal", CALL_BUILTIN_3_1}, {f_length, "length", CALL_BUILTIN_1_1}, }; -struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; +static struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; + +block builtins_bind(block b) { + return gen_cbinding(&builtins, b); +} diff --git a/c/builtin.h b/c/builtin.h index 5b0d3702..fe2ac6ac 100644 --- a/c/builtin.h +++ b/c/builtin.h @@ -2,7 +2,8 @@ #define BUILTIN_H #include "bytecode.h" +#include "compile.h" -extern struct symbol_table builtins; +block builtins_bind(block); #endif diff --git a/c/compile.h b/c/compile.h index bdaf6a88..28249e8f 100644 --- a/c/compile.h +++ b/c/compile.h @@ -1,3 +1,5 @@ +#ifndef COMPILE_H +#define COMPILE_H #include #include "bytecode.h" #include "opcode.h" @@ -47,3 +49,5 @@ int block_compile(block, struct locfile*, struct bytecode**); void block_free(block); + +#endif diff --git a/c/main.c b/c/main.c index f87a5112..b65d820f 100644 --- a/c/main.c +++ b/c/main.c @@ -21,7 +21,7 @@ struct bytecode* jq_compile(const char* str) { int nerrors = jq_parse(&locations, &program); if (nerrors == 0) { block_append(&program, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK))); - program = gen_cbinding(&builtins, program); + program = builtins_bind(program); nerrors = block_compile(program, &locations, &bc); block_free(program); } From 84ea129f26e46a0e38dd630f6d02cad41b983808 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 17 Sep 2012 19:41:41 +0100 Subject: [PATCH 071/284] Better support for appending strings in JV. --- c/jv.c | 59 ++++++++++++++++++++++++++++++++++++++++-------------- c/jv.h | 2 ++ c/testdata | 4 ++-- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/c/jv.c b/c/jv.c index 786e7b26..595484e7 100644 --- a/c/jv.c +++ b/c/jv.c @@ -340,6 +340,7 @@ typedef struct { // high 31 bits are length, low bit is a flag // indicating whether hash has been computed. uint32_t length_hashed; + uint32_t alloc_length; char data[]; } jvp_string; @@ -350,19 +351,19 @@ static jvp_string* jvp_string_ptr(jv_complex* a) { static jvp_string* jvp_string_alloc(uint32_t size) { jvp_string* s = malloc(sizeof(jvp_string) + size + 1); s->refcnt.count = 1; - s->length_hashed = size << 1; + s->alloc_length = size; return s; } static jv_complex jvp_string_new(const char* data, uint32_t length) { jvp_string* s = jvp_string_alloc(length); + s->length_hashed = length << 1; memcpy(s->data, data, length); s->data[length] = 0; jv_complex r = {&s->refcnt, {0,0}}; return r; } - static void jvp_string_free(jv_complex* s) { if (jvp_refcnt_dec(s)) { jvp_string* str = jvp_string_ptr(s); @@ -385,16 +386,37 @@ static uint32_t jvp_string_length(jvp_string* s) { return s->length_hashed >> 1; } -static jv_complex jvp_string_concat(jvp_string* a, jvp_string* b) { - uint32_t la = jvp_string_length(a), lb = jvp_string_length(b); - jvp_string* s = jvp_string_alloc(la + lb); - memcpy(s->data, a->data, la); - memcpy(s->data + la, b->data, lb); - s->data[la + lb] = 0; - jv_complex r = {&s->refcnt, {0,0}}; +static uint32_t jvp_string_remaining_space(jvp_string* s) { + uint32_t r = s->alloc_length - jvp_string_length(s); + assert(r >= 0); return r; } +static void jvp_string_append(jv_complex* string, const char* data, uint32_t len) { + jvp_string* s = jvp_string_ptr(string); + uint32_t currlen = jvp_string_length(s); + + if (jvp_refcnt_unshared(string) && + jvp_string_remaining_space(s) >= len) { + // the next string fits at the end of a + memcpy(s->data + currlen, data, len); + s->data[currlen + len] = 0; + s->length_hashed = (currlen + len) << 1; + } else { + // allocate a bigger buffer and copy + uint32_t allocsz = (currlen + len) * 2; + if (allocsz < 32) allocsz = 32; + jvp_string* news = jvp_string_alloc(allocsz); + news->length_hashed = (currlen + len) << 1; + memcpy(news->data, s->data, currlen); + memcpy(news->data + currlen, data, len); + news->data[currlen + len] = 0; + jvp_string_free(string); + jv_complex r = {&news->refcnt, {0,0}}; + *string = r; + } +} + static const uint32_t HASH_SEED = 0x432A9843; static uint32_t rotl32 (uint32_t x, int8_t r){ @@ -507,15 +529,22 @@ const char* jv_string_value(jv j) { } jv jv_string_concat(jv a, jv b) { - jv j; - j.kind = JV_KIND_STRING; - j.val.complex = jvp_string_concat(jvp_string_ptr(&a.val.complex), - jvp_string_ptr(&b.val.complex)); - jv_free(a); + jvp_string* sb = jvp_string_ptr(&b.val.complex); + jvp_string_append(&a.val.complex, sb->data, jvp_string_length(sb)); jv_free(b); - return j; + return a; } +jv jv_string_append_buf(jv a, const char* buf, int len) { + jvp_string_append(&a.val.complex, buf, len); + return a; +} + +jv jv_string_append_str(jv a, const char* str) { + return jv_string_append_buf(a, str, strlen(str)); +} + + jv jv_string_fmt(const char* fmt, ...) { int size = 1024; while (1) { diff --git a/c/jv.h b/c/jv.h index ec23262c..295369e8 100644 --- a/c/jv.h +++ b/c/jv.h @@ -80,6 +80,8 @@ uint32_t jv_string_hash(jv); const char* jv_string_value(jv); jv jv_string_concat(jv, jv); jv jv_string_fmt(const char*, ...); +jv jv_string_append_buf(jv a, const char* buf, int len); +jv jv_string_append_str(jv a, const char* str); jv jv_object(); jv jv_object_get(jv object, jv key); diff --git a/c/testdata b/c/testdata index e17f2bb7..c0afbeae 100644 --- a/c/testdata +++ b/c/testdata @@ -159,9 +159,9 @@ null "asdfasdf" {"a":1, "b":2, "c":3} -"asdf" + "jkl;" + . +"asdf" + "jkl;" + . + . + . "some string" -"asdfjkl;some string" +"asdfjkl;some stringsome stringsome string" "\u0000\u0020\u0000" + . "\u0000\u0020\u0000" From 9c15ad20218cdc03fb825773d6ea40b04c756471 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 17 Sep 2012 20:08:55 +0100 Subject: [PATCH 072/284] Support rendering a JSON value to a string buffer. --- c/jv.c | 1 - c/jv.h | 3 +- c/jv_print.c | 146 ++++++++++++++++++++++++++++++++++----------------- c/main.c | 5 ++ 4 files changed, 106 insertions(+), 49 deletions(-) diff --git a/c/jv.c b/c/jv.c index 595484e7..51070636 100644 --- a/c/jv.c +++ b/c/jv.c @@ -544,7 +544,6 @@ jv jv_string_append_str(jv a, const char* str) { return jv_string_append_buf(a, str, strlen(str)); } - jv jv_string_fmt(const char* fmt, ...) { int size = 1024; while (1) { diff --git a/c/jv.h b/c/jv.h index 295369e8..e67d614a 100644 --- a/c/jv.h +++ b/c/jv.h @@ -105,7 +105,8 @@ jv jv_object_iter_value(jv, int); int jv_get_refcnt(jv); enum { JV_PRINT_PRETTY = 1, JV_PRINT_ASCII = 2 }; -void jv_dump(jv, int); +void jv_dump(jv, int flags); +jv jv_dump_string(jv, int flags); jv jv_parse(const char* string); jv jv_parse_sized(const char* string, int length); diff --git a/c/jv_print.c b/c/jv_print.c index f1ec92fb..64bf178a 100644 --- a/c/jv_print.c +++ b/c/jv_print.c @@ -1,47 +1,70 @@ #include "jv.h" #include #include -#include +#include #include "jv_dtoa.h" #include "jv_unicode.h" -static void jv_dump_string(jv str, int ascii_only) { +static void put_buf(const char* s, int len, FILE* fout, jv* strout) { + if (strout) { + *strout = jv_string_append_buf(*strout, s, len); + } else { + fwrite(s, 1, len, fout); + } +} + +static void put_char(char c, FILE* fout, jv* strout) { + put_buf(&c, 1, fout, strout); +} + +static void put_str(const char* s, FILE* fout, jv* strout) { + put_buf(s, strlen(s), fout, strout); +} + +static void put_space(int n, FILE* fout, jv* strout) { + while (n--) { + put_char(' ', fout, strout); + } +} + +static void jvp_dump_string(jv str, int ascii_only, FILE* F, jv* S) { assert(jv_get_kind(str) == JV_KIND_STRING); const char* i = jv_string_value(str); const char* end = i + jv_string_length(jv_copy(str)); int c = 0; + char buf[32]; while ((i = jvp_utf8_next(i, end, &c))) { assert(c != -1); int unicode_escape = 0; if (0x20 <= c && c <= 0x7E) { // printable ASCII if (c == '"' || c == '\\') { - putchar('\\'); + put_char('\\', F, S); } - putchar(c); + put_char(c, F, S); } else if (c < 0x20 || c == 0x7F) { // ASCII control character switch (c) { case '\b': - putchar('\\'); - putchar('b'); + put_char('\\', F, S); + put_char('b', F, S); break; case '\t': - putchar('\\'); - putchar('t'); + put_char('\\', F, S); + put_char('t', F, S); break; case '\r': - putchar('\\'); - putchar('r'); + put_char('\\', F, S); + put_char('r', F, S); break; case '\n': - putchar('\\'); - putchar('n'); + put_char('\\', F, S); + put_char('n', F, S); break; case '\f': - putchar('\\'); - putchar('f'); + put_char('\\', F, S); + put_char('f', F, S); break; default: unicode_escape = 1; @@ -52,13 +75,14 @@ static void jv_dump_string(jv str, int ascii_only) { } if (unicode_escape) { if (c <= 0xffff) { - printf("\\u%04x", c); + sprintf(buf, "\\u%04x", c); } else { c -= 0x10000; - printf("\\u%04x\\u%04x", - 0xD800 | ((c & 0xffc00) >> 10), - 0xDC00 | (c & 0x003ff)); + sprintf(buf, "\\u%04x\\u%04x", + 0xD800 | ((c & 0xffc00) >> 10), + 0xDC00 | (c & 0x003ff)); } + put_str(buf, F, S); } } assert(c != -1); @@ -66,78 +90,97 @@ static void jv_dump_string(jv str, int ascii_only) { enum { INDENT = 2 }; -static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent) { +static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FILE* F, jv* S) { char buf[JVP_DTOA_FMT_MAX_LEN]; switch (jv_get_kind(x)) { case JV_KIND_INVALID: assert(0 && "Invalid value"); break; case JV_KIND_NULL: - printf("null"); + put_str("null", F, S); break; case JV_KIND_FALSE: - printf("false"); + put_str("false", F, S); break; case JV_KIND_TRUE: - printf("true"); + put_str("true", F, S); break; case JV_KIND_NUMBER: { double d = jv_number_value(x); if (d != d) { // JSON doesn't have NaN, so we'll render it as "null" - printf("null"); + put_str("null", F, S); } else { // Normalise infinities to something we can print in valid JSON if (d > DBL_MAX) d = DBL_MAX; if (d < -DBL_MAX) d = -DBL_MAX; - printf("%s", jvp_dtoa_fmt(C, buf, d)); + put_str(jvp_dtoa_fmt(C, buf, d), F, S); } break; } case JV_KIND_STRING: - // FIXME: all sorts of broken - putchar('"'); - jv_dump_string(x, 0); - putchar('"'); + put_char('"', F, S); + jvp_dump_string(x, 0, F, S); + put_char('"', F, S); break; case JV_KIND_ARRAY: { if (jv_array_length(jv_copy(x)) == 0) { - printf("[]"); + put_str("[]", F, S); break; } - printf("["); - if (flags & JV_PRINT_PRETTY) printf("\n%*s", indent+INDENT, ""); + put_str("[", F, S); + if (flags & JV_PRINT_PRETTY) { + put_char('\n', F, S); + put_space(indent+INDENT, F, S); + } for (int i=0; i Date: Mon, 17 Sep 2012 20:14:07 +0100 Subject: [PATCH 073/284] Add a "tostring" function. --- c/builtin.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/c/builtin.c b/c/builtin.c index 375e3252..97738656 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -129,6 +129,14 @@ static void f_tonumber(jv input[], jv output[]) { } } +static void f_tostring(jv input[], jv output[]) { + if (jv_get_kind(input[0]) == JV_KIND_STRING) { + output[0] = input[0]; + } else { + output[0] = jv_dump_string(input[0], 0); + } +} + struct cfunction function_list[] = { {f_true, "true", CALL_BUILTIN_1_1}, {f_false, "false", CALL_BUILTIN_1_1}, @@ -138,6 +146,7 @@ struct cfunction function_list[] = { {f_multiply, "_multiply", CALL_BUILTIN_3_1}, {f_divide, "_divide", CALL_BUILTIN_3_1}, {f_tonumber, "tonumber", CALL_BUILTIN_1_1}, + {f_tostring, "tostring", CALL_BUILTIN_1_1}, {f_equal, "_equal", CALL_BUILTIN_3_1}, }; struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; From 3db27b01a1ee58180e1c97592ceac24d0e434f0a Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 17 Sep 2012 20:41:57 +0100 Subject: [PATCH 074/284] First pass at string interpolation. Requires a lexer hack, but a surprisingly un-hideous one. The lexer maintains a stack of bracket characters so that it can match parens/brackets/braces to tell where a subexp nested in a string actually ends. --- c/lexer.l | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++- c/parser.y | 23 +++++++++++++++- 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/c/lexer.l b/c/lexer.l index dd93f497..94196146 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -11,11 +11,23 @@ %} +%s IN_PAREN +%s IN_BRACKET +%s IN_BRACE +%s IN_QQINTERP +%x IN_QQSTRING +%{ + static int enter(int opening, int state, yyscan_t yyscanner); + static int try_exit(int closing, int state, yyscan_t yyscanner); +%} + %option noyywrap nounput noinput nodefault %option reentrant %option extra-type="int" %option bison-bridge bison-locations %option prefix="jq_yy" +%option stack + %% @@ -37,7 +49,16 @@ "*=" { return SETMULT; } "/=" { return SETDIV; } "//=" { return SETDEFINEDOR; } -"."|"="|";"|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"+"|"-"|"*"|"/"|"\$" { return yytext[0];} +"."|"="|";"|","|":"|"|"|"+"|"-"|"*"|"/"|"\$" { return yytext[0];} + +"["|"{"|"(" { + return enter(yytext[0], YY_START, yyscanner); +} + +"]"|"}"|")" { + return try_exit(yytext[0], YY_START, yyscanner); +} + \"(\\.|[^\\\"])*\" | -?[0-9.]+([eE][+-]?[0-9]+)? { @@ -48,6 +69,25 @@ yylval->literal = jv_invalid_with_msg(jv_string("Unterminated string")); return LITERAL; } + +"@(" { + yy_push_state(IN_QQSTRING, yyscanner); + return QQSTRING_START; +} + +{ + "%(" { + return enter(QQSTRING_INTERP_START, YY_START, yyscanner); + } + [a-z]+ { + yylval->literal = jv_string_sized(yytext, yyleng); + return QQSTRING_TEXT; + } + ")" { + yy_pop_state(yyscanner); + return QQSTRING_END; + } +} [[:alnum:]]+ { yylval->literal = jv_string(yytext); return IDENT;} @@ -63,3 +103,38 @@ "false" { return FALSE; } "null" { return NULL; } */ +static int try_exit(int c, int state, yyscan_t yyscanner) { + char match = 0; + int ret; + switch (state) { + case IN_PAREN: match = ret = ')'; break; + case IN_BRACKET: match = ret = ']'; break; + case IN_BRACE: match = ret = '}'; break; + + case IN_QQINTERP: + match = ')'; + ret = QQSTRING_INTERP_END; + break; + } + assert(match); + if (match == c) { + yy_pop_state(yyscanner); + return ret; + } else { + // FIXME: should we pop? Give a better error at least + return INVALID_CHARACTER; + } +} + +static int enter(int c, int currstate, yyscan_t yyscanner) { + int state = 0; + switch (c) { + case '(': state = IN_PAREN; break; + case '[': state = IN_BRACKET; break; + case '{': state = IN_BRACE; break; + case QQSTRING_INTERP_START: state = IN_QQINTERP; break; + } + assert(state); + yy_push_state(state, yyscanner); + return c; +} diff --git a/c/parser.y b/c/parser.y index d8780a87..2684a26e 100644 --- a/c/parser.y +++ b/c/parser.y @@ -61,6 +61,12 @@ %token SETDIV "/=" %token SETDEFINEDOR "//=" +%token QQSTRING_START +%token QQSTRING_TEXT +%token QQSTRING_INTERP_START +%token QQSTRING_INTERP_END +%token QQSTRING_END + /* revolting hack */ %left ';' %left '|' @@ -74,7 +80,7 @@ %left '*' '/' -%type Exp Term MkDict MkDictPair ExpD ElseBody +%type Exp Term MkDict MkDictPair ExpD ElseBody QQString %{ #include "lexer.yy.h" #define FAIL(loc, msg) \ @@ -264,11 +270,26 @@ Exp "==" Exp { $$ = gen_binop($1, $3, EQ); } | +QQSTRING_START QQString QQSTRING_END { + $$ = $2; +} | + Term { $$ = $1; } +QQString: +/* empty */ { + $$ = gen_op_const(LOADK, jv_string("")); +} | +QQString QQSTRING_TEXT { + $$ = gen_binop($1, gen_op_const(LOADK, $2), '+'); +} | +QQString QQSTRING_INTERP_START Exp QQSTRING_INTERP_END { + $$ = gen_binop($1, $3, '+'); +} + ElseBody: "elif" Exp "then" Exp ElseBody { From 297a0679d1f7268e7ef0be8653748f8d22b8bda8 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 17 Sep 2012 20:59:34 +0100 Subject: [PATCH 075/284] Redefine true and false. Define empty, distict from null. This might be the most philosophical commit. I shall ponder it. true, false, null, empty now defined as bytecoded builtins rather than calls out to C functions. --- c/builtin.c | 57 +++++++++++++++++++++++++++++++++++------------------ c/testdata | 4 ++++ 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/c/builtin.c b/c/builtin.c index e8c51cd7..5b329fbd 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -1,19 +1,5 @@ #include "builtin.h" - -static void f_false(jv input[], jv output[]) { - jv_free(input[0]); - output[0] = jv_false(); -} - -static void f_true(jv input[], jv output[]) { - jv_free(input[0]); - output[0] = jv_true(); -} - -static void f_null(jv input[], jv output[]) { - jv_free(input[0]); - output[0] = jv_null(); -} +#include "compile.h" static void f_plus(jv input[], jv output[]) { jv_free(input[0]); @@ -151,10 +137,30 @@ static void f_tostring(jv input[], jv output[]) { } } -struct cfunction function_list[] = { - {f_true, "true", CALL_BUILTIN_1_1}, - {f_false, "false", CALL_BUILTIN_1_1}, - {f_null, "null", CALL_BUILTIN_1_1}, +static block j_empty() { + return gen_op_block_defn(CLOSURE_CREATE, "empty", gen_op_simple(BACKTRACK)); +} + +static block j_false() { + return gen_op_block_defn(CLOSURE_CREATE, "false", + block_join(gen_op_const(LOADK, jv_false()), + gen_op_simple(RET))); +} + +static block j_true() { + return gen_op_block_defn(CLOSURE_CREATE, "true", + block_join(gen_op_const(LOADK, jv_true()), + gen_op_simple(RET))); +} + +static block j_null() { + return gen_op_block_defn(CLOSURE_CREATE, "null", + block_join(gen_op_const(LOADK, jv_null()), + gen_op_simple(RET))); +} + + +static struct cfunction function_list[] = { {f_plus, "_plus", CALL_BUILTIN_3_1}, {f_minus, "_minus", CALL_BUILTIN_3_1}, {f_multiply, "_multiply", CALL_BUILTIN_3_1}, @@ -164,8 +170,21 @@ struct cfunction function_list[] = { {f_equal, "_equal", CALL_BUILTIN_3_1}, {f_length, "length", CALL_BUILTIN_1_1}, }; + static struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; +typedef block (*bytecoded_builtin)(); +static bytecoded_builtin bytecoded_builtins[] = { + j_empty, + j_false, + j_true, + j_null, +}; + + block builtins_bind(block b) { + for (int i=0; i Date: Mon, 17 Sep 2012 21:08:43 +0100 Subject: [PATCH 076/284] Make "not" a builtin function rather than syntax. Fixes a really awkward grammar issue. --- c/builtin.c | 7 +++++++ c/compile.c | 7 +------ c/compile.h | 2 +- c/lexer.l | 1 - c/parser.y | 5 ----- c/testdata | 2 +- 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/c/builtin.c b/c/builtin.c index 5b329fbd..ddac58f9 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -159,6 +159,12 @@ static block j_null() { gen_op_simple(RET))); } +static block j_not() { + return gen_op_block_defn(CLOSURE_CREATE, "not", + block_join(gen_condbranch(gen_op_const(LOADK, jv_false()), + gen_op_const(LOADK, jv_true())), + gen_op_simple(RET))); +} static struct cfunction function_list[] = { {f_plus, "_plus", CALL_BUILTIN_3_1}, @@ -179,6 +185,7 @@ static bytecoded_builtin bytecoded_builtins[] = { j_false, j_true, j_null, + j_not, }; diff --git a/c/compile.c b/c/compile.c index c45d45a1..023acb95 100644 --- a/c/compile.c +++ b/c/compile.c @@ -361,7 +361,7 @@ block gen_definedor(block a, block b) { return c; } -static block gen_condbranch(block iftrue, block iffalse) { +block gen_condbranch(block iftrue, block iffalse) { block b = gen_noop(); block_append(&iftrue, gen_op_target(JUMP, iffalse)); block_append(&b, gen_op_target(JUMP_F, iftrue)); @@ -398,11 +398,6 @@ block gen_or(block a, block b) { return code; } -block gen_not(block a) { - return block_join(a, gen_condbranch(gen_op_const(LOADK, jv_false()), - gen_op_const(LOADK, jv_true()))); -} - block gen_cond(block cond, block iftrue, block iffalse) { block b = gen_op_simple(DUP); block_append(&b, cond); diff --git a/c/compile.h b/c/compile.h index 28249e8f..411654fe 100644 --- a/c/compile.h +++ b/c/compile.h @@ -32,9 +32,9 @@ block gen_both(block a, block b); block gen_collect(block expr); block gen_assign(block expr); block gen_definedor(block a, block b); +block gen_condbranch(block iftrue, block iffalse); block gen_and(block a, block b); block gen_or(block a, block b); -block gen_not(block a); block gen_cond(block cond, block iftrue, block iffalse); diff --git a/c/lexer.l b/c/lexer.l index 94196146..412d9065 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -40,7 +40,6 @@ "elif" { return ELSE_IF; } "and" { return AND; } "or" { return OR; } -"not" { return NOT; } "end" { return END; } "//" { return DEFINEDOR; } "|=" { return SETPIPE; } diff --git a/c/parser.y b/c/parser.y index 2684a26e..822a3385 100644 --- a/c/parser.y +++ b/c/parser.y @@ -53,7 +53,6 @@ %token END "end" %token AND "and" %token OR "or" -%token NOT "not" %token SETPIPE "|=" %token SETPLUS "+=" %token SETMINUS "-=" @@ -210,10 +209,6 @@ Exp "and" Exp { $$ = gen_and($1, $3); } | -"not" Exp { - $$ = gen_not($2); -} | - Exp "//" Exp { $$ = gen_definedor($1, $3); } | diff --git a/c/testdata b/c/testdata index c83ef9c5..72367bbf 100644 --- a/c/testdata +++ b/c/testdata @@ -331,6 +331,6 @@ def inc(x): x |= .+1; inc(.[].a) [false,true] [false,false] -[.[] | not .] +[.[] | not] [1,0,false,null,true,"hello"] [false,false,true,true,false,false] From eab9c4e587e33ed5e506c5fdc9e3094987220074 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 17 Sep 2012 21:43:10 +0100 Subject: [PATCH 077/284] Fix debugging code in execute.c so that debug jq compiles again. --- c/execute.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/c/execute.c b/c/execute.c index 8426d3ca..eba2f1df 100644 --- a/c/execute.c +++ b/c/execute.c @@ -170,7 +170,7 @@ jv jq_next() { param = forkable_stack_peek_next(&data_stk, param); } if (!param) break; - jv_dump(jv_copy(param->sv.value)); + jv_dump(jv_copy(param->sv.value), 0); printf("<%d>", jv_get_refcnt(param->sv.value)); } @@ -246,7 +246,7 @@ jv jq_next() { jv* var = frame_local_var(fp, v); #if JQ_DEBUG printf("V%d = ", v); - jv_dump(jv_copy(*var)); + jv_dump(jv_copy(*var), 0); printf("\n"); #endif stack_push(stackval_replace(stack_pop(), jv_copy(*var))); @@ -261,7 +261,7 @@ jv jq_next() { stackval val = stack_pop(); #if JQ_DEBUG printf("V%d = ", v); - jv_dump(jv_copy(val.value)); + jv_dump(jv_copy(val.value), 0); printf("\n"); #endif jv_free(*var); From cbdeddbab8cd1206a04cab33fab50d1c9b55eaf7 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 17 Sep 2012 22:04:32 +0100 Subject: [PATCH 078/284] Make the code compile with warnings-as-errors. -Wextra found a bona-fide bug: signed/unsigned comparison in a stack overflow check. --- c/Makefile | 2 +- c/builtin.c | 2 +- c/execute.c | 4 +--- c/forkable_stack.h | 3 ++- c/gen_utf8_tables.py | 2 +- c/jv.c | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/c/Makefile b/c/Makefile index c80642dc..ddd49aea 100644 --- a/c/Makefile +++ b/c/Makefile @@ -1,4 +1,4 @@ -CC=gcc -Wall -std=gnu99 -ggdb -Wno-unused-function +CC=gcc -Werror -Wextra -Wall -Wno-unused-parameter -std=gnu99 -ggdb -Wno-unused-function .PHONY: all clean all: parsertest diff --git a/c/builtin.c b/c/builtin.c index ddac58f9..86951890 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -190,7 +190,7 @@ static bytecoded_builtin bytecoded_builtins[] = { block builtins_bind(block b) { - for (int i=0; istk = 0; } -static void* forkable_stack_push(struct forkable_stack* s, size_t size) { +static void* forkable_stack_push(struct forkable_stack* s, size_t sz_size) { + int size = (int)sz_size; forkable_stack_check(s); int curr = s->pos < s->savedlimit ? s->pos : s->savedlimit; if (curr - size < 0) { diff --git a/c/gen_utf8_tables.py b/c/gen_utf8_tables.py index 9d8dc3c0..2179222d 100644 --- a/c/gen_utf8_tables.py +++ b/c/gen_utf8_tables.py @@ -5,7 +5,7 @@ mask = lambda n: (1 << n) - 1 def print_table(type, name, t): assert len(t) == 256 - print "const static",type, name+"[]", "=" + print "static const",type, name+"[]", "=" first = True for i in range(0,len(t),16): print (" {" if i == 0 else " ") +\ diff --git a/c/jv.c b/c/jv.c index 51070636..2d91366b 100644 --- a/c/jv.c +++ b/c/jv.c @@ -387,8 +387,8 @@ static uint32_t jvp_string_length(jvp_string* s) { } static uint32_t jvp_string_remaining_space(jvp_string* s) { + assert(s->alloc_length >= jvp_string_length(s)); uint32_t r = s->alloc_length - jvp_string_length(s); - assert(r >= 0); return r; } From 49cf2e67feedab2f5eda9575d7b5cc10cb74d385 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 17 Sep 2012 22:32:06 +0100 Subject: [PATCH 079/284] Recursive functions + bugfix for stack reallocation. --- c/compile.c | 7 +++++++ c/compile.h | 1 + c/forkable_stack.h | 24 ++++++++++++++++-------- c/parser.y | 4 ++-- c/testdata | 6 ++++++ 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/c/compile.c b/c/compile.c index 023acb95..952aff3b 100644 --- a/c/compile.c +++ b/c/compile.c @@ -164,6 +164,13 @@ block gen_op_block_defn(opcode op, const char* name, block block) { return inst_block(i); } +static void block_bind_subblock(block binder, block body, int bindflags); +block gen_op_block_defn_rec(opcode op, const char* name, block blk) { + block b = gen_op_block_defn(op, name, blk); + block_bind_subblock(b, b, OP_IS_CALL_PSEUDO | OP_HAS_BINDING); + return b; +} + block gen_op_block_unbound(opcode op, const char* name) { assert(opcode_describe(op)->flags & OP_IS_CALL_PSEUDO); inst* i = inst_new(op); diff --git a/c/compile.h b/c/compile.h index 411654fe..ce27b4b8 100644 --- a/c/compile.h +++ b/c/compile.h @@ -23,6 +23,7 @@ block gen_op_target(opcode op, block target); block gen_op_var_unbound(opcode op, const char* name); block gen_op_var_bound(opcode op, block binder); block gen_op_block_defn(opcode op, const char* name, block block); +block gen_op_block_defn_rec(opcode op, const char* name, block block); block gen_op_block_unbound(opcode op, const char* name); block gen_op_call(opcode op, block arglist); block gen_op_symbol(opcode op, const char* name); diff --git a/c/forkable_stack.h b/c/forkable_stack.h index d485d227..5bfad8a9 100644 --- a/c/forkable_stack.h +++ b/c/forkable_stack.h @@ -6,7 +6,9 @@ #include struct forkable_stack_header { - int next; + /* distance in bytes between this header and the header + of the next object on the stack */ + int next_delta; }; #define FORKABLE_STACK_HEADER struct forkable_stack_header fk_header_ @@ -54,11 +56,12 @@ static void forkable_stack_free(struct forkable_stack* s) { } static void* forkable_stack_push(struct forkable_stack* s, size_t sz_size) { + assert(sz_size > 0 && sz_size % sizeof(struct forkable_stack_header) == 0); int size = (int)sz_size; forkable_stack_check(s); int curr = s->pos < s->savedlimit ? s->pos : s->savedlimit; if (curr - size < 0) { - assert(0); + //assert(0); int oldlen = s->length; s->length = (size + oldlen + 1024) * 2; s->stk = realloc(s->stk, s->length); @@ -68,9 +71,11 @@ static void* forkable_stack_push(struct forkable_stack* s, size_t sz_size) { s->savedlimit += shift; curr += shift; } - void* ret = (void*)(s->stk + curr - size); - ((struct forkable_stack_header*)ret)->next = s->pos; - s->pos = curr - size; + int newpos = curr - size; + assert(newpos < s->pos); + void* ret = (void*)(s->stk + newpos); + ((struct forkable_stack_header*)ret)->next_delta = s->pos - newpos; + s->pos = newpos; forkable_stack_check(s); return ret; } @@ -84,8 +89,11 @@ static void* forkable_stack_peek(struct forkable_stack* s) { static void* forkable_stack_peek_next(struct forkable_stack* s, void* top) { forkable_stack_check(s); struct forkable_stack_header* elem = top; - if (elem->next < s->length) { - return (void*)(s->stk + elem->next); + int elempos = (char*)top - s->stk; + assert(elempos >= 0 && elempos < s->length); + assert(elempos + elem->next_delta <= s->length); + if (elempos + elem->next_delta < s->length) { + return (void*)(s->stk + elempos + elem->next_delta); } else { return 0; } @@ -100,7 +108,7 @@ static int forkable_stack_pop_will_free(struct forkable_stack* s) { static void forkable_stack_pop(struct forkable_stack* s) { forkable_stack_check(s); struct forkable_stack_header* elem = forkable_stack_peek(s); - s->pos = elem->next; + s->pos += elem->next_delta; } diff --git a/c/parser.y b/c/parser.y index 822a3385..4492d185 100644 --- a/c/parser.y +++ b/c/parser.y @@ -165,14 +165,14 @@ program: Exp { *answer = $1; } Exp: "def" IDENT ':' Exp ';' Exp { block body = block_join($4, gen_op_simple(RET)); - $$ = block_bind(gen_op_block_defn(CLOSURE_CREATE, jv_string_value($2), body), + $$ = block_bind(gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body), $6, OP_IS_CALL_PSEUDO); jv_free($2); } | "def" IDENT '(' IDENT ')' ':' Exp ';' Exp { block body = block_bind(gen_op_block_unbound(CLOSURE_PARAM, jv_string_value($4)), block_join($7, gen_op_simple(RET)), OP_IS_CALL_PSEUDO); - $$ = block_bind(gen_op_block_defn(CLOSURE_CREATE, jv_string_value($2), body), $9, OP_IS_CALL_PSEUDO); + $$ = block_bind(gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body), $9, OP_IS_CALL_PSEUDO); jv_free($2); jv_free($4); } | diff --git a/c/testdata b/c/testdata index 72367bbf..7357ccb2 100644 --- a/c/testdata +++ b/c/testdata @@ -262,6 +262,12 @@ def id(x):x; 2000 as $x | def f(x):1 as $x | id([$x, x, x]); def g(x): 100 as $x 999999999 [[110.0, 130.0], [210.0, 130.0], [110.0, 230.0], [210.0, 230.0], [120.0, 160.0], [220.0, 160.0], [120.0, 260.0], [220.0, 260.0]] +# test recursion +def fac: if . == 1 then 1 else . * (. - 1 | fac) end; [.[] | fac] +[1,2,3,4] +[1,2,6,24] + + # # Assignment # From f13865d7a11d1aa6322a28e46eaaa463d823f44e Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 17 Sep 2012 22:37:51 +0100 Subject: [PATCH 080/284] Fix a precedence bug. a == b or c == d should obviously parse as (a==b) or (c==d). --- c/parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/parser.y b/c/parser.y index 4492d185..fd5dfbc7 100644 --- a/c/parser.y +++ b/c/parser.y @@ -72,9 +72,9 @@ %left ',' %right "//" %nonassoc '=' SETPIPE SETPLUS SETMINUS SETMULT SETDIV SETDEFINEDOR -%nonassoc EQ %left OR %left AND +%nonassoc EQ %left '+' '-' %left '*' '/' From 7d8d97933fda9e3a35eb850da6274fef9884a710 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 17 Sep 2012 23:06:48 +0100 Subject: [PATCH 081/284] Builtin function 'type'. --- c/builtin.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/c/builtin.c b/c/builtin.c index 86951890..74264f40 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -137,6 +137,11 @@ static void f_tostring(jv input[], jv output[]) { } } +static void f_type(jv input[], jv output[]) { + output[0] = jv_string(jv_kind_name(jv_get_kind(input[0]))); + jv_free(input[0]); +} + static block j_empty() { return gen_op_block_defn(CLOSURE_CREATE, "empty", gen_op_simple(BACKTRACK)); } @@ -175,6 +180,7 @@ static struct cfunction function_list[] = { {f_tostring, "tostring", CALL_BUILTIN_1_1}, {f_equal, "_equal", CALL_BUILTIN_3_1}, {f_length, "length", CALL_BUILTIN_1_1}, + {f_type, "type", CALL_BUILTIN_1_1}, }; static struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; From 5b9bb64a888bbf45e1cfe0dae3159e9bb80e3009 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 18 Sep 2012 09:43:44 +0100 Subject: [PATCH 082/284] -Werror was a little overzealous. Older versions of gcc warn about random things. -Werror makes the built fail on such compilers. --- c/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/Makefile b/c/Makefile index ddd49aea..7f58c617 100644 --- a/c/Makefile +++ b/c/Makefile @@ -1,4 +1,4 @@ -CC=gcc -Werror -Wextra -Wall -Wno-unused-parameter -std=gnu99 -ggdb -Wno-unused-function +CC=gcc -Wextra -Wall -Wno-missing-field-initializers -Wno-unused-parameter -std=gnu99 -ggdb -Wno-unused-function .PHONY: all clean all: parsertest From 940f8c427097d15d8d9227ce0b0c9c78360c4325 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 18 Sep 2012 10:17:38 +0100 Subject: [PATCH 083/284] Builtin functions defined in jq. --- c/builtin.c | 25 +++++++++++++++++++++--- c/compile.c | 15 ++++++++++++++- c/compile.h | 1 + c/main.c | 3 +-- c/parser.y | 55 +++++++++++++++++++++++++++++++++++++++-------------- 5 files changed, 79 insertions(+), 20 deletions(-) diff --git a/c/builtin.c b/c/builtin.c index 74264f40..6d0235e7 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -1,5 +1,9 @@ +#include #include "builtin.h" #include "compile.h" +#include "parser.h" +#include "locfile.h" + static void f_plus(jv input[], jv output[]) { jv_free(input[0]); @@ -183,7 +187,7 @@ static struct cfunction function_list[] = { {f_type, "type", CALL_BUILTIN_1_1}, }; -static struct symbol_table builtins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; +static struct symbol_table cbuiltins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; typedef block (*bytecoded_builtin)(); static bytecoded_builtin bytecoded_builtins[] = { @@ -194,10 +198,25 @@ static bytecoded_builtin bytecoded_builtins[] = { j_not, }; +static const char* jq_builtins[] = { + "def map(f): [.[] | f];" +}; + block builtins_bind(block b) { + block builtins = gen_noop(); for (unsigned i=0; inext) { + if ((opcode_describe(curr->op)->flags & bindflags) != bindflags) { + return 0; + } + } + return 1; +} + static void block_bind_subblock(block binder, block body, int bindflags) { assert(block_is_single(binder)); assert((opcode_describe(binder.first->op)->flags & bindflags) == bindflags); @@ -260,8 +270,11 @@ static void block_bind_subblock(block binder, block body, int bindflags) { } block block_bind(block binder, block body, int bindflags) { + assert(block_has_only_binders(binder, bindflags)); bindflags |= OP_HAS_BINDING; - block_bind_subblock(binder, body, bindflags); + for (inst* curr = binder.first; curr; curr = curr->next) { + block_bind_subblock(inst_block(curr), body, bindflags); + } return block_join(binder, body); } diff --git a/c/compile.h b/c/compile.h index ce27b4b8..5390420b 100644 --- a/c/compile.h +++ b/c/compile.h @@ -43,6 +43,7 @@ block gen_cbinding(struct symbol_table* functions, block b); void block_append(block* b, block b2); block block_join(block a, block b); +int block_has_only_binders(block, int bindflags); block block_bind(block binder, block body, int bindflags); int block_compile(block, struct locfile*, struct bytecode**); diff --git a/c/main.c b/c/main.c index c9188b3e..0a9eefe8 100644 --- a/c/main.c +++ b/c/main.c @@ -1,13 +1,12 @@ #include #include #include "compile.h" -#include "parser.tab.h" #include "builtin.h" #include "jv.h" #include "jv_parse.h" #include "locfile.h" +#include "parser.h" -int jq_parse(struct locfile* source, block* answer); void jq_init(struct bytecode* bc, jv value); jv jq_next(); diff --git a/c/parser.y b/c/parser.y index fd5dfbc7..73972e79 100644 --- a/c/parser.y +++ b/c/parser.y @@ -79,7 +79,7 @@ %left '*' '/' -%type Exp Term MkDict MkDictPair ExpD ElseBody QQString +%type Exp Term MkDict MkDictPair ExpD ElseBody QQString FuncDef FuncDefs %{ #include "lexer.yy.h" #define FAIL(loc, msg) \ @@ -160,21 +160,25 @@ static block gen_update(block a, block op, int optype) { %} %% -program: Exp { *answer = $1; } +TopLevel: +Exp { + *answer = $1; +} | +FuncDefs { + *answer = $1; +} + +FuncDefs: +/* empty */ { + $$ = gen_noop(); +} | +FuncDef FuncDefs { + $$ = block_join($1, $2); +} Exp: -"def" IDENT ':' Exp ';' Exp { - block body = block_join($4, gen_op_simple(RET)); - $$ = block_bind(gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body), - $6, OP_IS_CALL_PSEUDO); - jv_free($2); -} | - -"def" IDENT '(' IDENT ')' ':' Exp ';' Exp { - block body = block_bind(gen_op_block_unbound(CLOSURE_PARAM, jv_string_value($4)), block_join($7, gen_op_simple(RET)), OP_IS_CALL_PSEUDO); - $$ = block_bind(gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body), $9, OP_IS_CALL_PSEUDO); - jv_free($2); - jv_free($4); +FuncDef Exp %prec ';' { + $$ = block_bind($1, $2, OP_IS_CALL_PSEUDO); } | Term "as" '$' IDENT '|' Exp { @@ -273,6 +277,19 @@ Term { $$ = $1; } +FuncDef: +"def" IDENT ':' Exp ';' { + block body = block_join($4, gen_op_simple(RET)); + $$ = gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body); + jv_free($2); +} | + +"def" IDENT '(' IDENT ')' ':' Exp ';' { + block body = block_bind(gen_op_block_unbound(CLOSURE_PARAM, jv_string_value($4)), block_join($7, gen_op_simple(RET)), OP_IS_CALL_PSEUDO); + $$ = gen_op_block_defn_rec(CLOSURE_CREATE, jv_string_value($2), body); + jv_free($2); + jv_free($4); +} QQString: /* empty */ { @@ -405,3 +422,13 @@ int jq_parse(struct locfile* locations, block* answer) { } return errors; } + +int jq_parse_library(struct locfile* locations, block* answer) { + int errs = jq_parse(locations, answer); + if (errs) return errs; + if (!block_has_only_binders(*answer, OP_IS_CALL_PSEUDO)) { + locfile_locate(locations, UNKNOWN_LOCATION, "error: library should only have function definitions, not a main expression"); + return 1; + } + return 0; +} From 8f0c91c03289b25e8cad82270f9fea0c2eab7b7b Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 18 Sep 2012 12:58:29 +0100 Subject: [PATCH 084/284] Add a missing file from prev commit --- c/parser.h | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 c/parser.h diff --git a/c/parser.h b/c/parser.h new file mode 100644 index 00000000..25eff019 --- /dev/null +++ b/c/parser.h @@ -0,0 +1,7 @@ +#ifndef PARSER_H +#define PARSER_H + +int jq_parse(struct locfile* source, block* answer); +int jq_parse_library(struct locfile* locations, block* answer); + +#endif From 8041ce31192af8b54e83691372f23b0b9637234c Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 18 Sep 2012 12:58:39 +0100 Subject: [PATCH 085/284] Add the builtin 'select' function. --- c/builtin.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/c/builtin.c b/c/builtin.c index 6d0235e7..f291a95e 100644 --- a/c/builtin.c +++ b/c/builtin.c @@ -199,24 +199,25 @@ static bytecoded_builtin bytecoded_builtins[] = { }; static const char* jq_builtins[] = { - "def map(f): [.[] | f];" + "def map(f): [.[] | f];", + "def select(f): if f then . else empty end;", }; block builtins_bind(block b) { - block builtins = gen_noop(); - for (unsigned i=0; i=0; i--) { struct locfile src; locfile_init(&src, jq_builtins[i], strlen(jq_builtins[i])); block funcs; int nerrors = jq_parse_library(&src, &funcs); assert(!nerrors); - block_append(&builtins, funcs); + b = block_bind(funcs, b, OP_IS_CALL_PSEUDO); locfile_free(&src); } + block builtins = gen_noop(); + for (unsigned i=0; i Date: Tue, 18 Sep 2012 13:22:22 +0100 Subject: [PATCH 086/284] Slightly better string interpolation. --- c/lexer.l | 24 +++++++++++++++++++++--- c/parser.y | 8 ++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/c/lexer.l b/c/lexer.l index 412d9065..07cba83c 100644 --- a/c/lexer.l +++ b/c/lexer.l @@ -78,14 +78,32 @@ "%(" { return enter(QQSTRING_INTERP_START, YY_START, yyscanner); } - [a-z]+ { - yylval->literal = jv_string_sized(yytext, yyleng); - return QQSTRING_TEXT; + "%"[^(] { + return INVALID_CHARACTER; } ")" { yy_pop_state(yyscanner); return QQSTRING_END; } + "\\"[)%] { + char text[2] = {yytext[1], 0}; + yylval->literal = jv_string(text); + return QQSTRING_TEXT; + } + (\\[^u)%]|\\u[a-zA-Z0-9]{0,4})+ { + /* pass escapes to the json parser */ + jv escapes = jv_string_fmt("\"%.*s\"", yyleng, yytext); + yylval->literal = jv_parse_sized(jv_string_value(escapes), jv_string_length(jv_copy(escapes))); + jv_free(escapes); + return QQSTRING_TEXT; + } + [^\\)%]+ { + yylval->literal = jv_string_sized(yytext, yyleng); + return QQSTRING_TEXT; + } + . { + return INVALID_CHARACTER; + } } diff --git a/c/parser.y b/c/parser.y index 73972e79..b47c3574 100644 --- a/c/parser.y +++ b/c/parser.y @@ -102,7 +102,7 @@ int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, block* answer, int* errors, if (tok == INVALID_CHARACTER) { FAIL(*yylloc, "Invalid character"); } else { - if (tok == LITERAL && !jv_is_valid(yylval->literal)) { + if ((tok == LITERAL || tok == QQSTRING_TEXT) && !jv_is_valid(yylval->literal)) { jv msg = jv_invalid_get_msg(jv_copy(yylval->literal)); if (jv_get_kind(msg) == JV_KIND_STRING) { FAIL(*yylloc, jv_string_value(msg)); @@ -147,6 +147,10 @@ static block gen_binop(block a, block b, int op) { return c; } +static block gen_format(block a) { + return block_join(a, gen_op_call(CALL_1_1, gen_op_block_unbound(CLOSURE_REF, "tostring"))); +} + static block gen_update(block a, block op, int optype) { block assign = a; block_append(&assign, gen_op_simple(DUP)); @@ -299,7 +303,7 @@ QQString QQSTRING_TEXT { $$ = gen_binop($1, gen_op_const(LOADK, $2), '+'); } | QQString QQSTRING_INTERP_START Exp QQSTRING_INTERP_END { - $$ = gen_binop($1, $3, '+'); + $$ = gen_binop($1, gen_format($3), '+'); } From a4eea165bbab6d13f89b59707e835d58b7014a66 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 18 Sep 2012 17:44:43 +0100 Subject: [PATCH 087/284] Move everything around - delete old Haskell code, clean up build. --- .gitignore | 8 +- JQ.hs | 157 --------------------- Lexer.x | 101 ------------- Main.hs | 22 --- c/Makefile => Makefile | 20 +-- Parser.y | 78 ---------- c/builtin.c => builtin.c | 0 c/builtin.h => builtin.h | 0 c/bytecode.c => bytecode.c | 0 c/bytecode.h => bytecode.h | 0 c/compile.c => compile.c | 0 c/compile.h => compile.h | 0 c/execute.c => execute.c | 0 c/forkable_stack.h => forkable_stack.h | 0 c/frame_layout.h => frame_layout.h | 0 c/gen_utf8_tables.py => gen_utf8_tables.py | 0 c/jv.c => jv.c | 0 c/jv.h => jv.h | 0 c/jv_dtoa.c => jv_dtoa.c | 0 c/jv_dtoa.h => jv_dtoa.h | 0 c/jv_parse.c => jv_parse.c | 0 c/jv_parse.h => jv_parse.h | 0 c/jv_print.c => jv_print.c | 0 c/jv_test.c => jv_test.c | 0 c/jv_unicode.c => jv_unicode.c | 2 +- c/jv_unicode.h => jv_unicode.h | 0 c/lexer.l => lexer.l | 2 +- c/locfile.h => locfile.h | 0 c/main.c => main.c | 0 c/opcode.c => opcode.c | 0 c/opcode.h => opcode.h | 0 c/opcode_list.h => opcode_list.h | 0 c/parser.h => parser.h | 0 c/parser.y => parser.y | 2 +- c/testdata => testdata | 0 35 files changed, 16 insertions(+), 376 deletions(-) delete mode 100644 JQ.hs delete mode 100644 Lexer.x delete mode 100644 Main.hs rename c/Makefile => Makefile (50%) delete mode 100644 Parser.y rename c/builtin.c => builtin.c (100%) rename c/builtin.h => builtin.h (100%) rename c/bytecode.c => bytecode.c (100%) rename c/bytecode.h => bytecode.h (100%) rename c/compile.c => compile.c (100%) rename c/compile.h => compile.h (100%) rename c/execute.c => execute.c (100%) rename c/forkable_stack.h => forkable_stack.h (100%) rename c/frame_layout.h => frame_layout.h (100%) rename c/gen_utf8_tables.py => gen_utf8_tables.py (100%) rename c/jv.c => jv.c (100%) rename c/jv.h => jv.h (100%) rename c/jv_dtoa.c => jv_dtoa.c (100%) rename c/jv_dtoa.h => jv_dtoa.h (100%) rename c/jv_parse.c => jv_parse.c (100%) rename c/jv_parse.h => jv_parse.h (100%) rename c/jv_print.c => jv_print.c (100%) rename c/jv_test.c => jv_test.c (100%) rename c/jv_unicode.c => jv_unicode.c (98%) rename c/jv_unicode.h => jv_unicode.h (100%) rename c/lexer.l => lexer.l (98%) rename c/locfile.h => locfile.h (100%) rename c/main.c => main.c (100%) rename c/opcode.c => opcode.c (100%) rename c/opcode.h => opcode.h (100%) rename c/opcode_list.h => opcode_list.h (100%) rename c/parser.h => parser.h (100%) rename c/parser.y => parser.y (99%) rename c/testdata => testdata (100%) diff --git a/.gitignore b/.gitignore index 130e618d..50e45cc8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,10 @@ *.o *~ -# Autogenerated by flex/bison -lexer.yy.* -parser.tab.* -parser.info +# Autogenerated +*.gen.* # Test binaries jv_test jv_parse -parsertest \ No newline at end of file +parsertest*~ diff --git a/JQ.hs b/JQ.hs deleted file mode 100644 index ca8df794..00000000 --- a/JQ.hs +++ /dev/null @@ -1,157 +0,0 @@ -module JQ where -import Text.JSON -import Text.JSON.String -import Data.Maybe -import Data.List (sortBy,sort,groupBy) -import Data.Function (on) -import Data.Ord (comparing) -import Control.Monad -import Control.Monad.Writer -import Control.Monad.List -import Control.Monad.Reader - -type Path = [Either Int String] - -type Program = JSValue -> [(JSValue, Path)] - -type JQ = ReaderT JSValue (WriterT Path []) - -runJQ :: JQ a -> JSValue -> [a] -runJQ prog val = map fst $ runWriterT $ runReaderT prog val - -(>|) :: JQ JSValue -> JQ a -> JQ a -a >| b = do - val <- a - local (const val) b - -collect :: JQ a -> JQ [a] -collect prog = do - arg <- ask - return $ runJQ prog arg - -collectPaths :: JQ a -> JQ [(a,Path)] -collectPaths prog = do - arg <- ask - return $ runWriterT $ runReaderT prog arg - -insert :: JSValue -> (JSValue, Path) -> JSValue -insert base (replace, []) = replace -insert (JSArray values) (replace, ((Left n):rest)) = JSArray values' - where - (left, (_:right)) = splitAt n values - values' = left ++ [replace] ++ right -insert (JSObject obj) (replace, ((Right k):rest))= JSObject $ toJSObject obj' - where - withoutK = filter ((/= k) . fst) $ fromJSObject obj - obj' = (k, replace):withoutK - - -eqj a b = JSBool $ a == b - - -liftp :: (JSValue -> JSValue) -> JQ JSValue -liftp f = liftM f ask - -idp = undefined -failp t = [] - -constp :: JSValue -> Program -constp t t' = idp t - -anyj :: [JSValue] -> Bool -anyj values = any isTrue values - where - isTrue (JSBool False) = False - isTrue (JSNull) = False - isTrue _ = True - -selectp prog = do - match <- collect prog - guard $ anyj match - ask - -constStr :: String -> JQ JSValue -constStr = return . JSString . toJSString - -constInt :: Int -> JQ JSValue -constInt = return . JSRational False . toRational - -updatep p = do - t <- ask - liftM (foldl insert t) $ collectPaths p - -arrayp prog = liftM JSArray $ collect prog - - -childp' :: JSValue -> JQ JSValue -childp' (JSArray values) = msum [tell [Left i] >> return v | (v,i) <- zip values [0..]] -childp' (JSObject obj) = msum [tell [Right k] >> return v | (k,v) <- fromJSObject obj] -childp' _ = mzero - -childp = ask >>= childp' - ---findp :: Program -> Program -findp prog = do - found <- collect prog - if anyj found then ask else childp >| findp prog - -groupp prog = do - list <- ask - case list of - JSArray values -> do - marked <- forM values $ \v -> do - m <- collect (return v >| prog) - return (m,v) - msum $ - map (return . JSArray . map snd) $ - groupBy ((==) `on` fst) $ - sortBy (comparing fst) $ - marked - _ -> return JSNull - - - - -withArray f (JSArray values) = JSArray $ f values -withArray f x = x - -callp "select" [p] = selectp p -callp "find" [p] = findp p -callp "set" [p] = updatep p -callp "sort" [] = liftp (withArray sort) -callp "group" [p] = groupp p - -lookupj :: JSValue -> JSValue -> JQ JSValue -lookupj (JSArray values) (JSRational _ n) = do - let idx = round n - tell [Left idx] - if idx >= 0 && idx < length values - then return $ values !! idx - else return $ JSNull -lookupj (JSObject obj) (JSString s) = do - tell [Right (fromJSString s)] - case (lookup (fromJSString s) (fromJSObject obj)) of - Just x -> return x - Nothing -> return JSNull -lookupj _ _ = mzero - - -plusj (JSRational _ n1) (JSRational _ n2) = JSRational True (n1 + n2) -plusj (JSString s1) (JSString s2) = JSString $ toJSString (fromJSString s1 ++ fromJSString s2) -plusj (JSArray a1) (JSArray a2) = JSArray $ a1 ++ a2 - - -js :: JSON a => a -> JSValue -js = showJSON - -index s = do - v <- ask - lookupj v (js s) - - -dictp progs = do - liftM (JSObject . toJSObject) $ forM progs $ \(k,v) -> do - JSString k' <- k - v' <- v - return (fromJSString k', v') - diff --git a/Lexer.x b/Lexer.x deleted file mode 100644 index 700c69e6..00000000 --- a/Lexer.x +++ /dev/null @@ -1,101 +0,0 @@ -{ -module Lexer where -import Control.Monad.Error -} - -%wrapper "monadUserState" - -$digit = 0-9 -$alpha = [a-zA-Z_] -@reserved = "."|"["|"]"|","|":"|"("|")"|"{"|"}"|"|"|"=="|"+" -@ident = $alpha [$alpha $digit]* -@string = \" ($printable)* \" - - -tokens :- - -<0> $white+ ; -<0> @reserved { tok TRes } -<0> @ident { tok TIdent } -<0> $digit+ { tok $ TInt . read } - - -<0> \" { enterString } - \" { leaveString } - ($printable # [\"\\]) { pushString id } - \\ [\"\\\/] { pushString (drop 1) } - \\ [nrt] { pushString (escape . drop 1) } --- \\ 'u' [0-9a-fA-F]{4} --- { pushString (parseUnicode . drop 2) } - --- @string { \s -> TString $ init $ tail s} - - -{ - -escape :: String -> String -escape "r" = "\r" -escape "n" = "\n" -escape "t" = "\t" - -getState :: Alex AlexState -getState = Alex $ \s -> Right (s, s) - -getUserState :: Alex AlexUserState -getUserState = liftM alex_ust getState - -setUserState :: AlexUserState -> Alex () -setUserState s' = Alex $ \s -> Right (s{alex_ust = s'}, ()) - -alexEOF = return $ Nothing - -enterString input len = do - setUserState [] - alexSetStartCode string - skip input len - -pushString f i@(p, _, s) len = do - buf <- getUserState - setUserState (buf ++ [f $ take len s]) - skip i len - -leaveString input len = do - s <- getUserState - alexSetStartCode 0 - return $ Just $ TString $ concat s - - -tok f (p,_,s) len = return $ Just $ f (take len s) -data Token = TRes String | TString String | TIdent String | TInt Int - -instance Show Token where - show (TRes t) = "token " ++ t - show (TString t) = "string " ++ t - show (TIdent t) = "identifier " ++ t - show (TInt t) = "integer " ++ show t - - -type AlexUserState = [String] - -alexInitUserState = undefined - -wrapError (Alex scanner) = Alex $ \s -> case scanner s of - Left message -> Left (message ++ " at " ++ showpos (alex_pos s)) - where - showpos (AlexPn off line col) = "line " ++ show line ++ ", column " ++ show col - x -> x - -scanner = do - tok <- wrapError alexMonadScan - case tok of - Nothing -> do - s <- getState - case alex_scd s of - 0 -> return [] - string -> alexError "Unterminated string literal" - Just tok -> liftM (tok:) scanner - -runLexer :: String -> Either String [Token] -runLexer input = runAlex input scanner - -} \ No newline at end of file diff --git a/Main.hs b/Main.hs deleted file mode 100644 index 695520cb..00000000 --- a/Main.hs +++ /dev/null @@ -1,22 +0,0 @@ -import Parser -import Lexer -import JQ -import Text.JSON -import Text.JSON.String -import System.Environment -import Control.Monad -import System.IO - - -parseJS :: String -> JSValue -parseJS s = case runGetJSON readJSValue s of - Left err -> error err - Right val -> val - - -main = do - [program] <- getArgs - json <- liftM parseJS $ hGetContents stdin - case runLexer program >>= runParser of - Left err -> putStrLn err - Right program -> mapM_ (putStrLn . encode) (runJQ program json) \ No newline at end of file diff --git a/c/Makefile b/Makefile similarity index 50% rename from c/Makefile rename to Makefile index 7f58c617..db63b777 100644 --- a/c/Makefile +++ b/Makefile @@ -8,23 +8,23 @@ clean: sed 's/.*`\(.*\)'\''.*/\1/' | grep -v '^all$$' | \ xargs rm -jv_utf8_tables.h: gen_utf8_tables.py +jv_utf8_tables.gen.h: gen_utf8_tables.py python $^ > $@ -lexer.yy.c: lexer.l - flex -o lexer.yy.c --header-file=lexer.yy.h lexer.l -lexer.yy.h: lexer.yy.c +lexer.gen.c: lexer.l + flex -o lexer.gen.c --header-file=lexer.gen.h lexer.l +lexer.gen.h: lexer.gen.c -parser.tab.c: parser.y lexer.yy.h - bison -W -d parser.y -v --report-file=parser.info -parser.tab.h: parser.tab.c +parser.gen.c: parser.y lexer.gen.h + bison -W -d parser.y -v --report-file=parser.gen.info -o $@ +parser.gen.h: parser.gen.c -jv_unicode.c: jv_utf8_tables.h +jv_unicode.c: jv_utf8_tables.gen.h -parsertest: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c +parsertest: parser.gen.c lexer.gen.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c $(CC) -DJQ_DEBUG=1 -o $@ $^ -jq: parser.tab.c lexer.yy.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c +jq: parser.gen.c lexer.gen.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c $(CC) -DJQ_DEBUG=0 -o $@ $^ jv_test: jv_test.c jv.c jv_print.c jv_dtoa.c jv_unicode.c diff --git a/Parser.y b/Parser.y deleted file mode 100644 index 544fe5b4..00000000 --- a/Parser.y +++ /dev/null @@ -1,78 +0,0 @@ -{ -module Parser where -import Lexer -import JQ -import Text.JSON -import Debug.Trace -import Data.List -import Control.Monad.Error -import Control.Monad.Reader -} - -%name runParser Exp -%tokentype { Token } - -%monad { Either String } -%error { \t -> fail $ "parse error: unexpected " ++ if null t then [] else (show $ head t) } - -%token - '|' { TRes "|" } - '.' { TRes "." } - '[' { TRes "[" } - ']' { TRes "]" } - '{' { TRes "{" } - '}' { TRes "}" } - '(' { TRes "(" } - ')' { TRes ")" } - ',' { TRes "," } - ':' { TRes ":" } - '==' { TRes "==" } - '+' { TRes "+" } - Ident { TIdent $$ } - String { TString $$ } - Int { TInt $$ } - -%left '|' -%left ',' -%nonassoc '==' -%left '+' - -%% - -Exp - : Exp '|' Exp { $1 >| $3 } - | Exp ',' Exp { $1 `mplus` $3 } - | Exp '==' Exp { liftM2 eqj $1 $3 } - | Exp '+' Exp { liftM2 plusj $1 $3 } - | Term { $1 } - -ExpD - : ExpD '|' ExpD { $1 >| $3 } - | ExpD '==' ExpD { liftM2 eqj $1 $3 } - | Term { $1 } - - -Term - : '.' { ask } - | Term '.' Ident { $1 >| index $3 } - | '.' Ident { index $2 } - | String { constStr $1 } - | Term '[' Exp ']' { do {t <- $1; i <- $3; lookupj t i} } - | Term '[' ']' { $1 >| childp } - | '(' Exp ')' { $2 } - | '[' Exp ']' { arrayp $2 } - | Int { constInt $1 } - | '{' MkDict '}' { dictp $2 } - | Ident '(' Exp ')' { callp $1 [$3] } - | Ident { callp $1 [] } - -MkDict - : { [] } - | MkDictPair { [$1] } - | MkDictPair ',' MkDict { $1:$3 } - -MkDictPair - : Ident ':' ExpD { (constStr $1, $3) } - | Ident { (constStr $1, index $1) } - | String ':' ExpD { (constStr $1, $3) } - | '(' Exp ')' ':' ExpD{ ($2, $5) } diff --git a/c/builtin.c b/builtin.c similarity index 100% rename from c/builtin.c rename to builtin.c diff --git a/c/builtin.h b/builtin.h similarity index 100% rename from c/builtin.h rename to builtin.h diff --git a/c/bytecode.c b/bytecode.c similarity index 100% rename from c/bytecode.c rename to bytecode.c diff --git a/c/bytecode.h b/bytecode.h similarity index 100% rename from c/bytecode.h rename to bytecode.h diff --git a/c/compile.c b/compile.c similarity index 100% rename from c/compile.c rename to compile.c diff --git a/c/compile.h b/compile.h similarity index 100% rename from c/compile.h rename to compile.h diff --git a/c/execute.c b/execute.c similarity index 100% rename from c/execute.c rename to execute.c diff --git a/c/forkable_stack.h b/forkable_stack.h similarity index 100% rename from c/forkable_stack.h rename to forkable_stack.h diff --git a/c/frame_layout.h b/frame_layout.h similarity index 100% rename from c/frame_layout.h rename to frame_layout.h diff --git a/c/gen_utf8_tables.py b/gen_utf8_tables.py similarity index 100% rename from c/gen_utf8_tables.py rename to gen_utf8_tables.py diff --git a/c/jv.c b/jv.c similarity index 100% rename from c/jv.c rename to jv.c diff --git a/c/jv.h b/jv.h similarity index 100% rename from c/jv.h rename to jv.h diff --git a/c/jv_dtoa.c b/jv_dtoa.c similarity index 100% rename from c/jv_dtoa.c rename to jv_dtoa.c diff --git a/c/jv_dtoa.h b/jv_dtoa.h similarity index 100% rename from c/jv_dtoa.h rename to jv_dtoa.h diff --git a/c/jv_parse.c b/jv_parse.c similarity index 100% rename from c/jv_parse.c rename to jv_parse.c diff --git a/c/jv_parse.h b/jv_parse.h similarity index 100% rename from c/jv_parse.h rename to jv_parse.h diff --git a/c/jv_print.c b/jv_print.c similarity index 100% rename from c/jv_print.c rename to jv_print.c diff --git a/c/jv_test.c b/jv_test.c similarity index 100% rename from c/jv_test.c rename to jv_test.c diff --git a/c/jv_unicode.c b/jv_unicode.c similarity index 98% rename from c/jv_unicode.c rename to jv_unicode.c index 375ad367..b1417a2a 100644 --- a/c/jv_unicode.c +++ b/jv_unicode.c @@ -1,7 +1,7 @@ #include #include #include "jv_unicode.h" -#include "jv_utf8_tables.h" +#include "jv_utf8_tables.gen.h" const char* jvp_utf8_next(const char* in, const char* end, int* codepoint) { if (in == end) { diff --git a/c/jv_unicode.h b/jv_unicode.h similarity index 100% rename from c/jv_unicode.h rename to jv_unicode.h diff --git a/c/lexer.l b/lexer.l similarity index 98% rename from c/lexer.l rename to lexer.l index 07cba83c..e604adab 100644 --- a/c/lexer.l +++ b/lexer.l @@ -1,6 +1,6 @@ %{ #include "compile.h" -#include "parser.tab.h" /* Generated by bison. */ +#include "parser.gen.h" /* Generated by bison. */ #define YY_USER_ACTION \ do { \ diff --git a/c/locfile.h b/locfile.h similarity index 100% rename from c/locfile.h rename to locfile.h diff --git a/c/main.c b/main.c similarity index 100% rename from c/main.c rename to main.c diff --git a/c/opcode.c b/opcode.c similarity index 100% rename from c/opcode.c rename to opcode.c diff --git a/c/opcode.h b/opcode.h similarity index 100% rename from c/opcode.h rename to opcode.h diff --git a/c/opcode_list.h b/opcode_list.h similarity index 100% rename from c/opcode_list.h rename to opcode_list.h diff --git a/c/parser.h b/parser.h similarity index 100% rename from c/parser.h rename to parser.h diff --git a/c/parser.y b/parser.y similarity index 99% rename from c/parser.y rename to parser.y index b47c3574..0fda65bd 100644 --- a/c/parser.y +++ b/parser.y @@ -81,7 +81,7 @@ %type Exp Term MkDict MkDictPair ExpD ElseBody QQString FuncDef FuncDefs %{ -#include "lexer.yy.h" +#include "lexer.gen.h" #define FAIL(loc, msg) \ do { \ location l = loc; \ diff --git a/c/testdata b/testdata similarity index 100% rename from c/testdata rename to testdata From cf134909fd20021f4f7628f1eb7c1ad11c4a4e62 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 18 Sep 2012 17:51:53 +0100 Subject: [PATCH 088/284] Documentation. Copious. --- docs/.gitignore | 6 + docs/Rakefile | 54 + docs/content/1.tutorial/default.yml | 239 + docs/content/2.download/default.yml | 52 + docs/content/3.manual/manual.yml | 688 ++ docs/content/index/index.yml | 12 + docs/public/.htaccess | 28 + .../bootstrap/css/bootstrap-responsive.css | 1058 +++ .../css/bootstrap-responsive.min.css | 9 + docs/public/bootstrap/css/bootstrap.css | 5774 +++++++++++++++++ docs/public/bootstrap/css/bootstrap.min.css | 9 + .../img/glyphicons-halflings-white.png | Bin 0 -> 8777 bytes .../bootstrap/img/glyphicons-halflings.png | Bin 0 -> 12799 bytes docs/public/bootstrap/js/bootstrap.js | 2027 ++++++ docs/public/bootstrap/js/bootstrap.min.js | 6 + docs/public/css/base.scss | 72 + docs/public/jq.png | Bin 0 -> 8195 bytes docs/public/robots.txt | 2 + docs/site.yml | 11 + docs/templates/default.liquid | 34 + docs/templates/index.liquid | 38 + docs/templates/manual.liquid | 109 + docs/templates/shared/_footer.liquid | 5 + docs/templates/shared/_head.liquid | 12 + docs/templates/shared/_header.liquid | 24 + 25 files changed, 10269 insertions(+) create mode 100644 docs/.gitignore create mode 100644 docs/Rakefile create mode 100644 docs/content/1.tutorial/default.yml create mode 100644 docs/content/2.download/default.yml create mode 100644 docs/content/3.manual/manual.yml create mode 100644 docs/content/index/index.yml create mode 100644 docs/public/.htaccess create mode 100644 docs/public/bootstrap/css/bootstrap-responsive.css create mode 100644 docs/public/bootstrap/css/bootstrap-responsive.min.css create mode 100644 docs/public/bootstrap/css/bootstrap.css create mode 100644 docs/public/bootstrap/css/bootstrap.min.css create mode 100644 docs/public/bootstrap/img/glyphicons-halflings-white.png create mode 100644 docs/public/bootstrap/img/glyphicons-halflings.png create mode 100644 docs/public/bootstrap/js/bootstrap.js create mode 100644 docs/public/bootstrap/js/bootstrap.min.js create mode 100644 docs/public/css/base.scss create mode 100644 docs/public/jq.png create mode 100644 docs/public/robots.txt create mode 100644 docs/site.yml create mode 100644 docs/templates/default.liquid create mode 100644 docs/templates/index.liquid create mode 100644 docs/templates/manual.liquid create mode 100644 docs/templates/shared/_footer.liquid create mode 100644 docs/templates/shared/_head.liquid create mode 100644 docs/templates/shared/_header.liquid diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..4e01195c --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +.sass-cache +output/* + +# Autogenerated from public/css/base.scss +public/css/base.css \ No newline at end of file diff --git a/docs/Rakefile b/docs/Rakefile new file mode 100644 index 00000000..b4e1d6d1 --- /dev/null +++ b/docs/Rakefile @@ -0,0 +1,54 @@ +require 'bonsai' +require 'liquid' +require 'maruku' +require 'json' + +module ExtraFilters + def markdownify(input) + Maruku.new(input).to_html + end + + def sanitize(input) + input.gsub(/[^a-zA-Z0-9_]/,"") + end + + def json(input) + input.to_json + end + + def unique(input) + @n = (@n || 0) + 1 + input + @n.to_s + end +end + +Liquid::Template.register_filter(ExtraFilters) + + +task :serve do + begin + Bonsai.log "Press Control+C to quit" + + require 'rack' + require 'sinatra' + require 'watch' + require 'launchy' + + Bonsai.root_dir = Dir.pwd + + server = fork { + app = Rack::Builder.app { + use Bonsai::StaticPassThrough, :root => Bonsai.root_dir + "/output", :urls => ["/"] + run Bonsai::DevelopmentServer + } + Rack::Handler.default.run(app, :Port => 5000) do + Launchy.open("http://localhost:5000/") + end + } + Watch.new("{content,templates,public}/**/*") { Bonsai::Exporter.process! } + rescue Interrupt + Process.kill("QUIT", server) + Process.wait(server) + exit + end +end diff --git a/docs/content/1.tutorial/default.yml b/docs/content/1.tutorial/default.yml new file mode 100644 index 00000000..5ba2df15 --- /dev/null +++ b/docs/content/1.tutorial/default.yml @@ -0,0 +1,239 @@ +headline: Tutorial +body: + - text: | + + Twitter have a JSON API, so let's play with that. This URL gets + us the last 5 tweets about JSON: + + - command: "curl 'http://search.twitter.com/search.json?q=json&rpp=5&include_entities=true'" + result: | + {"completed_in":0.108,"max_id":247677287108067328,"max_id_str":"247677287108067328","next_page":"?page=2&max_id=247677287108067328&q=json&rpp=5&include_entities=1","page":1,"query":"json","refresh_url":"?since_id=247677287108067328&q=json&include_entities=1","results":[{"created_at":"Mon, 17 Sep 2012 12:44:01 +0000","entities":{"hashtags":[],"urls":[{"url":"http:\/\/t.co\/XRvh1ZVw","expanded_url":"http:\/\/jase.im\/Ri7I0M","display_url":"jase.im\/Ri7I0M","indices":[112,132]}],"user_mentions":[{"screen_name":"imagemechanics","name":"Jason Cotterell","id":57271393,"id_str":"57271393","indices":[3,18]}]},"from_user":"_AaronNg","from_user_id":79771704,"from_user_id_str":"79771704","from_user_name":"NgChenChong","geo":null,"id":247677287108067328,"id_str":"247677287108067328","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2523558403\/ek8mo4j4beq84iw28gjl_normal.jpeg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2523558403\/ek8mo4j4beq84iw28gjl_normal.jpeg","source":"<a href="http:\/\/twitter.com\/">web<\/a>","text":"RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp:\/\/t.co\/XRvh1ZVw","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}, ... + + - text: | + + There's lots of info and no whitespace, so to make it a bit more + legible we pipe it through jq, telling jq to just spit the input + back at us using the expression `.`: + + + - command: "curl 'http://search.twitter.com/search.json?q=json&rpp=5&include_entities=true' | jq '.'" + result: | + + { + "since_id_str": "0", + "since_id": 0, + "results_per_page": 5, + "completed_in": 0.108, + "max_id": 247677287108067330, + "max_id_str": "247677287108067328", + "next_page": "?page=2&max_id=247677287108067328&q=json&rpp=5&include_entities=1", + "page": 1, + "query": "json", + "refresh_url": "?since_id=247677287108067328&q=json&include_entities=1", + "results": [ + { + "from_user_name": "NgChenChong", + "from_user_id_str": "79771704", + "from_user_id": 79771704, + "from_user": "_AaronNg", + "iso_language_code": "en", + "text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw", + "to_user": null + /* lots more fields... */ + }, + /* lots more results... */ + ] + } + + + - text: | + + Let's pull out the first tweet: + + + - command: "curl 'http://search.twitter.com/search.json?q=json&rpp=5&include_entities=true' | jq '.results[0]'" + result: | + { + "from_user_name": "NgChenChong", + "from_user_id_str": "79771704", + "from_user_id": 79771704, + "from_user": "_AaronNg", + "iso_language_code": "en", + "text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw", + "to_user": null + /* lots more fields... */ + }, + + - text: | + + For the rest of the examples, I'll leave out the `curl` command - it's not going to change. + + + There's still a lot of info we don't care about there, so we'll + restrict it down to the most interesting fields. + + + - command: "jq '.results[0] | {from_user, text}'" + result: | + { + "text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw", + "from_user": "_AaronNg" + } + + - text: | + + The `|` operator in jq feeds the output of one filter + (`.results[0]` which gets the first element of the results + array) into the input of another (`{from_user, text}` which + builds an object of those two fields). + + Now let's get the rest of the tweets: + + + + - command: "jq '.results[] | {from_user, text}'" + result: | + { + "text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw", + "from_user": "_AaronNg" + } + { + "text": "RT @_kud: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas> -- http://t.co/Lhp92IqD", + "from_user": "blouerat" + } + { + "text": "Dynamic Forms Mobile App by pmadiset: Few Forms details are hosted on our server in the form of JSON. This JSON ... http://t.co/7KALdWaX", + "from_user": "cebu_iphone" + } + { + "text": "iPhone 5 website insanity - Video compressing using JPEG, JSON, and <canvas> http://t.co/28Jesbio (Oh #Apple, U So #Awesome...)", + "from_user": "dieswaytoofast" + } + { + "text": "RT @umutm: A very nice web-based JSON editor - http://t.co/M70snaIf", + "from_user": "Leolik" + } + + + - text: | + + `.results[]` returns each element of the results array, one at a + time, which are all fed into `{from_user, text}`. + + + Data in jq is represented as streams of JSON values - every jq + expression runs for each value in its input stream, and can + produce any number of values to its output stream. + + Streams are serialised by just separating JSON values with + whitespace. This is a `cat`-friendly format - you can just join + two JSON streams together and get a valid JSON stream. + + If you want to get the output as a single array, you can tell jq to + "collect" all of the answers by wrapping the filter in square + brackets: + + - command: "jq '[.results[] | {from_user, text}]'" + result: | + [ + { + "text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw", + "from_user": "_AaronNg" + }, + { + "text": "RT @_kud: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas> -- http://t.co/Lhp92IqD", + "from_user": "blouerat" + }, + { + "text": "Dynamic Forms Mobile App by pmadiset: Few Forms details are hosted on our server in the form of JSON. This JSON ... http://t.co/7KALdWaX", + "from_user": "cebu_iphone" + }, + { + "text": "iPhone 5 website insanity - Video compressing using JPEG, JSON, and <canvas> http://t.co/28Jesbio (Oh #Apple, U So #Awesome...)", + "from_user": "dieswaytoofast" + }, + { + "text": "RT @umutm: A very nice web-based JSON editor - http://t.co/M70snaIf", + "from_user": "Leolik" + } + ] + + + - text: | + + - - - + + Next, let's try getting the URLs out of those API results as + well. In each tweet, the Twitter API includes a field called + "entities" which looks like this: + + { + "user_mentions": [], + "urls": [{ + "indices": [83, 103], + "display_url": "bit.ly/StniqT", + "expanded_url": "http://bit.ly/StniqT", + "url": "http://t.co/28Jesbio" + }], + "hashtags": [ + {"indices": [108, 114], "text": "Apple" }, + {"indices": [121, 129], "text": "Awesome"} + ] + } + + We want to pull out all of the "url" fields inside that array of url + objects, and make a simple list of strings to go along with the + "from_user" and "text" fields we already have. + + + + - command: "jq '.results[] | {from_user, text, urls: [.entities.urls[].url]}'" + result: | + { + "urls": [ + "http://t.co/XRvh1ZVw" + ], + "text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw", + "from_user": "_AaronNg" + } + { + "urls": [ + "http://t.co/Lhp92IqD" + ], + "text": "RT @_kud: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas> -- http://t.co/Lhp92IqD", + "from_user": "blouerat" + } + { + "urls": [ + "http://t.co/7KALdWaX" + ], + "text": "Dynamic Forms Mobile App by pmadiset: Few Forms details are hosted on our server in the form of JSON. This JSON ... http://t.co/7KALdWaX", + "from_user": "cebu_iphone" + } + { + "urls": [ + "http://t.co/28Jesbio" + ], + "text": "iPhone 5 website insanity - Video compressing using JPEG, JSON, and <canvas> http://t.co/28Jesbio (Oh #Apple, U So #Awesome...)", + "from_user": "dieswaytoofast" + } + { + "urls": [ + "http://t.co/M70snaIf" + ], + "text": "RT @umutm: A very nice web-based JSON editor - http://t.co/M70snaIf", + "from_user": "Leolik" + } + + + - text: | + + Here we're making an object as before, but this time the urls + field is being set to `[.entities.urls[].url]`, which collects + all of the URLs defined in the entities object. + + - text: | + + - - - + + asdf \ No newline at end of file diff --git a/docs/content/2.download/default.yml b/docs/content/2.download/default.yml new file mode 100644 index 00000000..03c9cb7f --- /dev/null +++ b/docs/content/2.download/default.yml @@ -0,0 +1,52 @@ +headline: Download jq +body: + + - text: | + + jq is written in C and has no runtime dependencies, so it should be + possible to build it for nearly any platform. Prebuilt binaries are + available for Linux (64-bit x86) and OS X. + + * [Download binary for 64-bit Linux](/download/linux/x68_64/jq) + * [Download binary for OS X](/download/osx/64/jq) + * [Download source](/download/source/jq.tgz) + + jq is licensed under the MIT license. For all of the gory + details, read the file `COPYING` in the source distribution. + + Hacking on jq + ============= + + If you want to work on jq, grab the source from + [https://github.com/stedolan/jq](https://github.com/stedolan/jq). + + + To build it from a git clone, you'll need to install a few + packages first: + + * [Flex](http://www.gnu.org/software/flex/) + * [Bison](http://www.gnu.org/software/bison/) + * [Python](http://www.python.org) + * [GCC](http://gcc.gnu.org) + * [Make](http://www.gnu.org/software/make) + + Most of these aren't necessary if you're just trying to compile + jq from the released tarball - that version has the + non-platform-specific build steps already done, so you'll only + need a C compiler and `make` to finish it off. + + For Linux systems, these will all be in your system's package + manager, and if you do development on the machine they're most + likely already installed. I have no idea how to get these + installed on OS X, you're on your own there. + + `flex` and `bison` are used to generate the lexer and parser for + jq, and some python scripts generate the UTF8 encoding tables + needed for JSON parsing. + + Building the documentation + -- + + jq's documentation is compiled into static HTML using + [Bonsai](http://www.tinytree.info). To view the documentation + locally, run `rake serve` from the docs/ subdirectory. \ No newline at end of file diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml new file mode 100644 index 00000000..20793976 --- /dev/null +++ b/docs/content/3.manual/manual.yml @@ -0,0 +1,688 @@ +headline: jq Manual +sections: + - title: Basics + body: "{ some *intro* text \n\n\n}\n" + entries: + - title: "`.`" + body: | + + The absolute simplest (and least interesting) jq expression + is `.`. This is a jq expression that takes its input and + produces it unchanged as output. + + Since jq by default pretty-prints all output, this trivial + program can be a useful way of formatting JSON output from, + say, `curl`. + + examples: + - program: '.' + input: '"Hello, world!"' + output: ['"Hello, world!"'] + + - title: "`.foo`" + body: | + + The simplest *useful* jq expression is .foo. When given a + JSON object (aka dictionary or hash) as input, it produces + the value at the key "foo", or null if there\'s none present. + + examples: + - program: '.foo' + input: '{"foo": 42, "bar": "less interesting data"}' + output: [42] + - program: '.foo' + input: '{"notfoo": true, "alsonotfoo": false}' + output: ['null'] + + - title: "`.[foo]`" + body: | + + You can also look up fields of an object using syntax like + `.["foo"]` (.foo above is a shorthand version of this). This + one works for arrays as well, if the key is an + integer. Arrays are zero-based (like javascript), so .[2] + returns the third element of the array. + + examples: + - program: '.[0]' + input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' + output: ['{"name":"JSON", "good":true}'] + + - program: '.[2]' + input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' + output: ['null'] + + - title: "`.[]`" + body: | + + If you use the `.[foo]` syntax, but omit the index + entirely, it will return *all* of the elements of an + array. Running `.[]` with the input `[1,2,3]` will produce the + numbers as three seperate results, rather than as a single + array. + + examples: + - program: '.[]' + input: '[{name":"JSON", "good":true}, {"name":"XML", "good":false}]' + output: + - '{"name":"JSON", "good":true}' + - '{"name":"XML", "good":false}' + + - program: '.[]' + input: '[]' + output: [] + + - title: "`,`" + body: | + + If two jq expressions are separated by a comma, then the + input will be fed into both and there will be multiple + outputs: first, all of the outputs produced by the left + expression, and then all of the outputs produced by the + right. For instance, jq expression `.foo, .bar`, produces + both the "foo" fields and "bar" fields as separate outputs. + + examples: + - program: '.foo, .bar' + input: '{"foo": 42, "bar": "something else", "baz": true}' + output: ['42', '"something else"'] + + - program: "[.user, .projects[]]" + input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' + output: ['"stedolan"', '"jq"', '"wikiflow"'] + + - program: '.[4,2]' + input: '["a","b","c","d","e"]' + output: ['"d"', '"c"'] + + - title: "`|`" + body: | + The | operator combines two jq expressions by feeding the output(s) of + the one on the left into the input of the one on the right. It\'s + pretty much the same as the Unix shell\'s pipe, if you\'re used to + that. + + If the one on the left produces multiple results, the one on + the right will be run for each of those results. So, the + expression `.[] | .foo` retrieves the "foo" field of each + element of the input array. + + examples: + - program: '.[] | .name' + input: '[{name":"JSON", "good":true}, {"name":"XML", "good":false}]' + output: ['"JSON"', '"XML"'] + + - title: Types and Values + body: | + + jq supports the same set of datatypes as JSON - numbers, + strings, booleans, arrays, objects (which in JSON-speak are + hashes with only string keys), and "null". + + Booleans, null, strings and numbers are written the same way as + in javascript. Just like everything else in jq, these simple + values take an input and produce an output - `42` is a valid jq + expression that takes an input, ignores it, and returns 42 + instead. + + entries: + - title: Array construction - `[]` + body: | + + As in JSON, `[]` is used to construct arrays, as in + `[1,2,3]`. The elements of the arrays can be any jq + expression. All of the results produced by all of the + expressions are collected into one big array. You can use it + to construct an array out of a known quantity of values (as + in `[.foo, .bar, .baz]`) or to "collect" all the results of a + jq expression into an array (as in `[.items[].name]`) + + Once you understand the "," operator, you can look at jq\'s array + syntax in a different light: the expression [1,2,3] is not using a + built-in syntax for comma-separated arrays, but is instead applying + the `[]` operator (collect results) to the expression 1,2,3 (which + produces three different results). + + If you have a jq expression `X` that produces four results, + then the expression `[X]` will produce a single result, an + array of four elements. + + examples: + - program: "[.user, .projects[]]" + input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' + output: ['["stedolan", "jq", "wikiflow"]'] + - title: Objects - `{}` + body: | + + Like JSON, `{}` is for constructing objects (aka + dictionaries or hashes), as in: `{"a": 42, "b": 17}`. + + If the keys are "sensible" (all alphabetic characters), then + the quotes can be left off. The value can be any expression + (although you may need to wrap it in parentheses if it\'s a + complicated one), which gets applied to the {} expression\'s + input (remember, all jq expressions have an input and an + output). + + {foo: .bar} + + will produce the JSON object `{"foo": 42}` if given the JSON + object `{"bar":42, "baz":43}`. You can use this to select + particular fields of an object: if the input is an object + with "user", "title", "id", and "content" fields and you + just want "user" and "title", you can write + + {user: .user, title: .title} + + Because that\'s so common, there\'s a shortcut syntax: `{user, title}`. + + If one of the expressions produces multiple results, + multiple dictionaries will be produced. If the input\'s + + {"user":"stedolan","titles":["JQ Primer", "More JQ"]} + + then the expression + + {user, title: .titles[]} + + will produce two outputs: + + {"user":"stedolan", "title": "JQ Primer"} + {"user":"stedolan", "title": "More JQ"} + + Putting parentheses around the key means it will be evaluated as an + expression. With the same input as above, + + {(.user): .titles} + + produces + + {"stedolan": ["JQ Primer", "More JQ"]} + + examples: + - program: '{user, title: .titles[]}' + input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' + output: + - '{"user":"stedolan", "title": "JQ Primer"}' + - '{"user":"stedolan", "title": "More JQ"}' + - program: '{(.user): .titles}' + input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' + output: ['{"stedolan": ["JQ Primer", "More JQ"]}'] + + - title: Builtin operators and functions + body: | + + Some jq operator (for instance, `+`) do different things + depending on the type of their arguments (arrays, numbers, + etc.). However, jq never does implicit type conversions. If you + try to add a string to an object you'll get an error message and + no result. + + entries: + - title: Addition - `+` + body: | + + The operator `+` takes two jq expressions, applies them both + to the same input, and adds the results together. What + "adding" means depends on the types involved: + + - **Numbers** are added by normal arithmetic. + + - **Arrays** are added by being concatenated into a larger array. + + - **Strings** are added by being joined into a larger string. + + - **Objects** are added by merging, that is, inserting all + the key-value pairs from both objects into a single + combined object. If both objects contain a value for the + same key, the object on the right of the `+` wins. + + examples: + - program: '.a + 1' + input: '{"a": 7}' + output: '{"a": 8}' + - program: '.a + .b' + input: '{"a": [1,2], "b": [3,4]}' + output: ['[1,2,3,4]'] + - program: '{a: 1} + {b: 2} + {c: 3} + {a: 42}' + input: 'null' + output: ['{"a": 42, "b": 2, "c": 3}'] + + - title: Subtraction - `-` + body: | + + As well as normal arithmetic subtraction on numbers, the `-` + operator can be used on arrays to remove all occurences of + the second array's elements from the first array. + + examples: + - program: '4 - .a' + input: '{"a":3}' + output: ['1'] + - program: . - ["xml", "yaml"] + input: '["xml", "yaml", "json"]' + output: ['["json"]'] + + - title: Multiplication, division - `*` and `/` + body: | + + These operators only work on numbers, and do the expected. + + examples: + - program: '10 / . * 3' + input: 5 + output: [6] + + - title: `length` + body: | + + The builtin function `length` gets the length of various + different types of value: + + - The length of a **string** is the number of Unicode + codepoints it contains (which will be the same as its + JSON-encoded length in bytes if it's pure ASCII). + + - The length of an **array** is the number of elements. + + - The length of an **object** is the number of key-value pairs. + + - The length of **null** is zero. + + examples: + - program: '.[] | length' + input: '[[1,2], "string", {"a":2}, null]' + output: [2, 6, 1, 0] + + - title: `tonumber` + body: | + + The `tonumber` function parses its input as a number. It + will convert correctly-formatted strings to their numeric + equivalent, leave numbers alone, and give an error on all other input. + + examples: + - program: '.[] | tonumber' + input: '[1, "1"]' + output: [1,1] + + - title: `tostring` + body: | + + The `tostring` function prints its input as a + string. Strings are left unchanged, and all other values are + JSON-encoded. + + examples: + - program: '.[] | tostring' + input: '[1, "1", [1]]' + output: ['"1"', '"1"', '"[1]"'] + + - title: "String interpolation - `@(text)`" + body: | + + jq supports an alternative syntax for strings. Instead of + "foo", you can write `@(foo)`. When using this syntax, + `%(expression)` may be used to insert the value of + `expression` into the string (converted with `tostring`). + + String interpolation does not occur for normal double-quoted + strings (like `"foo"`) in order to be fully compatible with + JSON. + + All of the usual JSON escapes (`\n`, `\r` and the like) work + inside `@()`-quoted strings, as well as `\%` and `\)` if + those characters are needed literally. + + examples: + - program: '@(The input was %(.), which is one less than %(.+1))' + input: '42' + output: ['"The input was 42, which is one less than 43"'] + + + + + + + - title: Conditionals and Comparisons + entries: + - title: `==`, `!=` + body: | + + The expression 'a == b' will produce 'true' if the result of a and b + are equal (that is, if they represent equivalent JSON documents) and + 'false' otherwise. In particular, strings are never considered equal + to numbers. If you're coming from Javascript, jq's == is like + Javascript's === - considering values equal only when they have the + same type as well as the same value. + + != is "not equal", and 'a != b' returns the opposite value of 'a == b' + + examples: + - program: '.[] == 1' + input: '[1, 1.0, "1", "banana"]' + output: ['[true, true, false, false]'] + + - title: if-then-else + body: | + + `if A then B else C end` will act the same as `B` if `A` + produces a value other than false or null, but act the same + as `C` otherwise. + + Checking for false or null is a simpler notion of + "truthiness" than is found in Javascript or Python, but it + means that you'll sometimes have to be more explicit about + the condition you want: you can't test whether, e.g. a + string is empty using `if .name then A else B end`, you'll + need something more like 'if (.name | count) > 0 then A else + B end' instead. + + If the condition A produces multiple results, it is + considered "true" if any of those results is not false or + null. If it produces zero results, it's considered false. + + More cases can be added to an if using `elif A then B` syntax. + + examples: + - program: |- + if . == 0 then + "zero" + elif . == 1 then + "one" + else + "many" + end + input: 2 + output: ['"many"'] + + - title: and/or/not + body: | + + jq supports the normal Boolean operators and/or/not. They have the + same standard of truth as if expressions - false and null are + considered "false values", and anything else is a "true value". + + If an operand of one of these operators produces multiple + results, the operator itself will produce a result for each input. + + `not` is in fact a builtin function rather than an operator, + so it is called as a filter to which things can be piped + rather than with special syntax, as in `.foo and .bar | + not`. + + These three only produce the values "true" and "false", and + so are only useful for genuine Boolean operations, rather + than the common Perl/Python/Ruby idiom of + "value_that_may_be_null or default". If you want to use this + form of "or", picking between two values rather than + evaluating a condition, see the "//" operator below. + + examples: + - program: '42 and "a string"' + input: 'null' + output: ['true'] + - program: '(true, false) or false' + input: 'null' + output: ['true', 'false'] + - program: '(true, false) and (true, false)' + input: 'null' + output: ['true', 'false', 'false', 'false'] + - program: '[true, false | not]' + input: 'null' + output: ['[false, true]'] + + - title: Alternative operator - `//` + body: | + + A jq expression of the form `a // b` produces the same + results as `a`, if `a` produces results other than `false` + and `null`. Otherwise, `a // b` produces the same results as `b`. + + This is useful for providing defaults: `.foo or 1` will + evaluate to `1` if there's no `.foo` element in the + input. It's similar to how `or` is sometimes used in Python + (jq's `or` operator is reserved for strictly Boolean + operations). + + examples: + - program: '.foo // 42' + input: '{"foo": 19}' + output: [19] + - program: '.foo // 42' + input: '{}' + output: [42] + + - title: Variables and Functions + body: | + Variables are an absolute necessity in most programming languages, but + they're relegated to an "advanced feature" in jq. + + In most languages, variables are the only means of passing around + data. If you calculate a value, and you want to use it more than once, + you'll need to store it in a variable. To pass a value to another part + of the program, you'll need that part of the program to define a + variable (as a function parameter, object member, or whatever) in + which to place the data. + + It is also possible to define functions in jq, although this is + is a feature whose biggest use is defining jq's standard library + (many jq functions such as `map` and `find` are in fact written + in jq). + + entries: + - title: Variables + body: | + + In jq, all jq expressions have an input and an output, so manual + plumbing is not necessary to pass a value from one part of a program + to the next. Many expressions, for instance `a + b`, pass their input + to two distinct subexpressions (here `a` and `b` are both passed the + same input), so variables aren't usually necessary in order to use a + value twice. + + For instance, calculating the average value of an array of numbers + requires a few variables in most languages - at least one to hold the + array, perhaps one for each element or for a loop counter. In jq, it's + simply `add / length` - the `sum` expression is given the array and + produces its sum, and the `count` expression is given the array and + produces its length. + + So, there's generally a cleaner way to solve most problems in jq that + defining variables. Still, sometimes they do make things easier, so jq + lets you define variables using `expression as $variable`. All + variable names start with `$`. Here's a slightly uglier version of the + array-averaging example: + + length as $array_length | add / $array_length + + We'll need a more complicated problem to find a situation where using + variables actually makes our lives easier. + + + Suppose we have an array of blog posts, with "author" and "title" + fields, and another object which is used to map author usernames to + real names. Our input looks like: + + {"posts": [{"title": "Frist psot", "author": "anon"}, + {"title": "A well-written article", "author": "person1"}], + "realnames": {"anon": "Anonymous Coward", + "person1": "Person McPherson"}} + + We want to produce the posts with the author field containing a real + name, as in: + + {"title": "Frist psot", "author": "Anonymous Coward"} + {"title": "A well-written article", "author": "Person McPherson"} + + We use a variable, $names, to store the realnames object, so that we + can refer to it later when looking up author usernames: + + .realnames as $names | .posts[] | {title, author: $names[.author]} + + The expression "asdf as $x" runs asdf, puts the result in $x, and + returns the original input. Apart from the side-effect of binding the + variable, it has the same effect as ".". + + Variables are scoped over the rest of the expression that defines + them, so + + .realnames as $names | (.posts[] | {title, author: $names[.author]}) + + will work, but + + (.realnames as $names | .posts[]) | {title, author: $names[.author]} + + won't. + + examples: + - program: '.bar as $x | .foo | . + $x' + input: '{"foo":10, "bar":200}' + output: ['210'] + + - title: 'Defining Functions' + body: | + + You can give a jq expression a name using "def" syntax: + + def increment: . + 1; + + From then on, `increment` is usable as a filter just like a + builtin function (in fact, this is how some of the builtins + are defined). A function may take arguments: + + def map(f): [.[] | f]; + + Arguments are passed as jq expressions, not as values. The + same argument may be referenced multiple times with + different inputs (here `f` is run for each element of the + input array). Arguments to a function work more like + callbacks than like value arguments. + + If you want the value-argument behaviour for defining simple + functions, you can just use a variable: + + def addvalue(f): f as $value | map(, + $value); + + With that definition, `addvalue(.foo)` will add the current + input's `.foo` field to each element of the array. + + examples: + - program: 'def addvalue(f): map(. + [$value]); addvalue(.[0])' + input: '[[1,2],[10,20]]' + output: ['[[1,2,1], [10,20,10]]'] + - program: 'def addvalue(f): f as $x | map (. + $x); addvalue(.[0])' + input: '[[1,2],[10,20]]' + output: ['[[1,2,[1,2]], [10,20,[1,2]]]'] + + + - title: Assignment + body: | + + Assignment works a little differently in jq than in most + programming languages. jq doesn't distinguish between references + to and copies of something - two objects or arrays are either + equal or not equal, without any further notion of being "the + same object" or "not the same object". + + If an object has two fields which are arrays, `.foo` and `.bar`, + and you append something to `.foo`, then `.bar` will not get + bigger. Even if you've just set `.bar = .foo`. If you're used to + programming in languages like Python, Java, Ruby, Javascript, + etc. then you can think of it as though jq does a full deep copy + of every object before it does the assignment (for performance, + it doesn't actually do that, but that's the general idea). + + entries: + - title: "`=`" + body: | + + The jq expression `.foo = 1` will take as input an object + and produce as output an object with the "foo" field set to + 1. There is no notion of "modifying" or "changing" something + in jq - all jq values are immutable. For instance, + + .foo = .bar | .foo.baz = 1 + + will not have the side-effect of setting .bar.baz to be set + to 1, as the similar-looking program in Javascript, Python, + Ruby or other languages would. Unlike these languages (but + like Haskell and some other functional languages), there is + no notion of two arrays or objects being "the same array" or + "the same object". They can be equal, or not equal, but if + we change one of them in no circumstances will the other + change behind our backs. + + This means that it's impossible to build circular values in + jq (such as an array whose first element is itself). This is + quite intentional, and ensures that anything a jq program + can produce can be represented in JSON. + + - title: "`|=`" + body: | + As well as the assignment operator '=', jq provides the "update" + operator '|=', which takes a jq expression on the right-hand side and + works out the new value for the property being assigned to by running + the old value through this expression. For instance, .foo |= .+1 will + build an object with the "foo" field set to the input's "foo" plus 1. + + This example should show the difference between '=' and '|=': + + Provide input '{"a": {"b": 10}, "b": 20}' to the programs: + + .a = .b + .a |= .b + + The former will set the "a" field of the input to the "b" field of the + input, and produce the output {"a": 20}. The latter will set the "a" + field of the input to the "a" field's "b" field, producing {"a": 10}. + + - title: "`+=`, `-=`, `*=`, `/=`, `//=`" + body: | + + jq has a few operators of the form `a op= b`, which are all + equivalent to `a |= . op b`. So, `+= 1` can be used to increment values. + + examples: + - program: .foo += 1 + input: '{"foo": 42}' + output: ['{"foo": 43}'] + + - title: Complex assignments + body: | + Lots more things are allowed on the left-hand side of a jq assignment + than in most langauges. We've already seen simple field accesses on + the left hand side, and it's no surprise that array accesses work just + as well: + + .posts[0].title = "JQ Manual" + + What may come as a surprise is that the expression on the left may + produce multiple results, referring to different points in the input + document: + + .posts[].comments |= . + ["this is great"] + + That example appends the string "this is great" to the "comments" + array of each post in the input (where the input is an object with a + field "posts" which is an array of posts). + + When jq encounters an assignment like 'a = b', it records the "path" + taken to select a part of the input document while executing a. This + path is then used to find which part of the input to change while + executing the assignment. Any jq expression may be used on the + left-hand side of an equals - whichever paths it selects from the + input will be where the assignment is performed. + + This is a very powerful operation. Suppose we wanted to add a comment + to blog posts, using the same "blog" input above. This time, we only + want to comment on the posts written by "stedolan". We can find those + posts using the "select" function described earlier: + + .posts[] | select(.author == "stedolan") + + The paths provided by this operation point to each of the posts that + "stedolan" wrote, and we can comment on each of them in the same way + that we did before: + + (.posts[] | select(.author == "stedolan") | .comments) |= . + ["terrible."] diff --git a/docs/content/index/index.yml b/docs/content/index/index.yml new file mode 100644 index 00000000..f0e7196e --- /dev/null +++ b/docs/content/index/index.yml @@ -0,0 +1,12 @@ +headline: jq + +blurb: | + + jq is a command-line JSON processor. + +body: | + + + + Go read the [tutorial](/tutorial) for more, or the [manual](/manual) + for *way* more. \ No newline at end of file diff --git a/docs/public/.htaccess b/docs/public/.htaccess new file mode 100644 index 00000000..7142064d --- /dev/null +++ b/docs/public/.htaccess @@ -0,0 +1,28 @@ +DirectoryIndex index.html +FileETag All + +# Compress all static assets + + # compress content with type html, text, and css + AddOutputFilterByType DEFLATE text/css text/html text/javascript application/javascript application/x-javascript text/js text/plain text/xml + + + # properly handle requests coming from behind proxies + Header append Vary User-Agent + + + +# Cache, aggressively + + ExpiresActive On + ExpiresDefault "access plus 10 days" + + + ExpiresDefault "access plus 10 years" + + + +# Mime-types +AddType application/vnd.ms-fontobject .eot +AddType font/ttf .ttf +AddType font/otf .otf \ No newline at end of file diff --git a/docs/public/bootstrap/css/bootstrap-responsive.css b/docs/public/bootstrap/css/bootstrap-responsive.css new file mode 100644 index 00000000..9259d26d --- /dev/null +++ b/docs/public/bootstrap/css/bootstrap-responsive.css @@ -0,0 +1,1058 @@ +/*! + * Bootstrap Responsive v2.1.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + line-height: 0; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.hidden { + display: none; + visibility: hidden; +} + +.visible-phone { + display: none !important; +} + +.visible-tablet { + display: none !important; +} + +.hidden-desktop { + display: none !important; +} + +.visible-desktop { + display: inherit !important; +} + +@media (min-width: 768px) and (max-width: 979px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important ; + } + .visible-tablet { + display: inherit !important; + } + .hidden-tablet { + display: none !important; + } +} + +@media (max-width: 767px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important; + } + .visible-phone { + display: inherit !important; + } + .hidden-phone { + display: none !important; + } +} + +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + line-height: 0; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 30px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 1170px; + } + .span12 { + width: 1170px; + } + .span11 { + width: 1070px; + } + .span10 { + width: 970px; + } + .span9 { + width: 870px; + } + .span8 { + width: 770px; + } + .span7 { + width: 670px; + } + .span6 { + width: 570px; + } + .span5 { + width: 470px; + } + .span4 { + width: 370px; + } + .span3 { + width: 270px; + } + .span2 { + width: 170px; + } + .span1 { + width: 70px; + } + .offset12 { + margin-left: 1230px; + } + .offset11 { + margin-left: 1130px; + } + .offset10 { + margin-left: 1030px; + } + .offset9 { + margin-left: 930px; + } + .offset8 { + margin-left: 830px; + } + .offset7 { + margin-left: 730px; + } + .offset6 { + margin-left: 630px; + } + .offset5 { + margin-left: 530px; + } + .offset4 { + margin-left: 430px; + } + .offset3 { + margin-left: 330px; + } + .offset2 { + margin-left: 230px; + } + .offset1 { + margin-left: 130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + line-height: 0; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.564102564102564%; + *margin-left: 2.5109110747408616%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.45299145299145%; + *width: 91.39979996362975%; + } + .row-fluid .span10 { + width: 82.90598290598291%; + *width: 82.8527914166212%; + } + .row-fluid .span9 { + width: 74.35897435897436%; + *width: 74.30578286961266%; + } + .row-fluid .span8 { + width: 65.81196581196582%; + *width: 65.75877432260411%; + } + .row-fluid .span7 { + width: 57.26495726495726%; + *width: 57.21176577559556%; + } + .row-fluid .span6 { + width: 48.717948717948715%; + *width: 48.664757228587014%; + } + .row-fluid .span5 { + width: 40.17094017094017%; + *width: 40.11774868157847%; + } + .row-fluid .span4 { + width: 31.623931623931625%; + *width: 31.570740134569924%; + } + .row-fluid .span3 { + width: 23.076923076923077%; + *width: 23.023731587561375%; + } + .row-fluid .span2 { + width: 14.52991452991453%; + *width: 14.476723040552828%; + } + .row-fluid .span1 { + width: 5.982905982905983%; + *width: 5.929714493544281%; + } + .row-fluid .offset12 { + margin-left: 105.12820512820512%; + *margin-left: 105.02182214948171%; + } + .row-fluid .offset12:first-child { + margin-left: 102.56410256410257%; + *margin-left: 102.45771958537915%; + } + .row-fluid .offset11 { + margin-left: 96.58119658119658%; + *margin-left: 96.47481360247316%; + } + .row-fluid .offset11:first-child { + margin-left: 94.01709401709402%; + *margin-left: 93.91071103837061%; + } + .row-fluid .offset10 { + margin-left: 88.03418803418803%; + *margin-left: 87.92780505546462%; + } + .row-fluid .offset10:first-child { + margin-left: 85.47008547008548%; + *margin-left: 85.36370249136206%; + } + .row-fluid .offset9 { + margin-left: 79.48717948717949%; + *margin-left: 79.38079650845607%; + } + .row-fluid .offset9:first-child { + margin-left: 76.92307692307693%; + *margin-left: 76.81669394435352%; + } + .row-fluid .offset8 { + margin-left: 70.94017094017094%; + *margin-left: 70.83378796144753%; + } + .row-fluid .offset8:first-child { + margin-left: 68.37606837606839%; + *margin-left: 68.26968539734497%; + } + .row-fluid .offset7 { + margin-left: 62.393162393162385%; + *margin-left: 62.28677941443899%; + } + .row-fluid .offset7:first-child { + margin-left: 59.82905982905982%; + *margin-left: 59.72267685033642%; + } + .row-fluid .offset6 { + margin-left: 53.84615384615384%; + *margin-left: 53.739770867430444%; + } + .row-fluid .offset6:first-child { + margin-left: 51.28205128205128%; + *margin-left: 51.175668303327875%; + } + .row-fluid .offset5 { + margin-left: 45.299145299145295%; + *margin-left: 45.1927623204219%; + } + .row-fluid .offset5:first-child { + margin-left: 42.73504273504273%; + *margin-left: 42.62865975631933%; + } + .row-fluid .offset4 { + margin-left: 36.75213675213675%; + *margin-left: 36.645753773413354%; + } + .row-fluid .offset4:first-child { + margin-left: 34.18803418803419%; + *margin-left: 34.081651209310785%; + } + .row-fluid .offset3 { + margin-left: 28.205128205128204%; + *margin-left: 28.0987452264048%; + } + .row-fluid .offset3:first-child { + margin-left: 25.641025641025642%; + *margin-left: 25.53464266230224%; + } + .row-fluid .offset2 { + margin-left: 19.65811965811966%; + *margin-left: 19.551736679396257%; + } + .row-fluid .offset2:first-child { + margin-left: 17.094017094017094%; + *margin-left: 16.98763411529369%; + } + .row-fluid .offset1 { + margin-left: 11.11111111111111%; + *margin-left: 11.004728132387708%; + } + .row-fluid .offset1:first-child { + margin-left: 8.547008547008547%; + *margin-left: 8.440625568285142%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 30px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 1156px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 1056px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 956px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 856px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 756px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 656px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 556px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 456px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 356px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 256px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 156px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 56px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } + .row-fluid .thumbnails { + margin-left: 0; + } +} + +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + line-height: 0; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 724px; + } + .span12 { + width: 724px; + } + .span11 { + width: 662px; + } + .span10 { + width: 600px; + } + .span9 { + width: 538px; + } + .span8 { + width: 476px; + } + .span7 { + width: 414px; + } + .span6 { + width: 352px; + } + .span5 { + width: 290px; + } + .span4 { + width: 228px; + } + .span3 { + width: 166px; + } + .span2 { + width: 104px; + } + .span1 { + width: 42px; + } + .offset12 { + margin-left: 764px; + } + .offset11 { + margin-left: 702px; + } + .offset10 { + margin-left: 640px; + } + .offset9 { + margin-left: 578px; + } + .offset8 { + margin-left: 516px; + } + .offset7 { + margin-left: 454px; + } + .offset6 { + margin-left: 392px; + } + .offset5 { + margin-left: 330px; + } + .offset4 { + margin-left: 268px; + } + .offset3 { + margin-left: 206px; + } + .offset2 { + margin-left: 144px; + } + .offset1 { + margin-left: 82px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + line-height: 0; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.7624309392265194%; + *margin-left: 2.709239449864817%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.43646408839778%; + *width: 91.38327259903608%; + } + .row-fluid .span10 { + width: 82.87292817679558%; + *width: 82.81973668743387%; + } + .row-fluid .span9 { + width: 74.30939226519337%; + *width: 74.25620077583166%; + } + .row-fluid .span8 { + width: 65.74585635359117%; + *width: 65.69266486422946%; + } + .row-fluid .span7 { + width: 57.18232044198895%; + *width: 57.12912895262725%; + } + .row-fluid .span6 { + width: 48.61878453038674%; + *width: 48.56559304102504%; + } + .row-fluid .span5 { + width: 40.05524861878453%; + *width: 40.00205712942283%; + } + .row-fluid .span4 { + width: 31.491712707182323%; + *width: 31.43852121782062%; + } + .row-fluid .span3 { + width: 22.92817679558011%; + *width: 22.87498530621841%; + } + .row-fluid .span2 { + width: 14.3646408839779%; + *width: 14.311449394616199%; + } + .row-fluid .span1 { + width: 5.801104972375691%; + *width: 5.747913483013988%; + } + .row-fluid .offset12 { + margin-left: 105.52486187845304%; + *margin-left: 105.41847889972962%; + } + .row-fluid .offset12:first-child { + margin-left: 102.76243093922652%; + *margin-left: 102.6560479605031%; + } + .row-fluid .offset11 { + margin-left: 96.96132596685082%; + *margin-left: 96.8549429881274%; + } + .row-fluid .offset11:first-child { + margin-left: 94.1988950276243%; + *margin-left: 94.09251204890089%; + } + .row-fluid .offset10 { + margin-left: 88.39779005524862%; + *margin-left: 88.2914070765252%; + } + .row-fluid .offset10:first-child { + margin-left: 85.6353591160221%; + *margin-left: 85.52897613729868%; + } + .row-fluid .offset9 { + margin-left: 79.8342541436464%; + *margin-left: 79.72787116492299%; + } + .row-fluid .offset9:first-child { + margin-left: 77.07182320441989%; + *margin-left: 76.96544022569647%; + } + .row-fluid .offset8 { + margin-left: 71.2707182320442%; + *margin-left: 71.16433525332079%; + } + .row-fluid .offset8:first-child { + margin-left: 68.50828729281768%; + *margin-left: 68.40190431409427%; + } + .row-fluid .offset7 { + margin-left: 62.70718232044199%; + *margin-left: 62.600799341718584%; + } + .row-fluid .offset7:first-child { + margin-left: 59.94475138121547%; + *margin-left: 59.838368402492065%; + } + .row-fluid .offset6 { + margin-left: 54.14364640883978%; + *margin-left: 54.037263430116376%; + } + .row-fluid .offset6:first-child { + margin-left: 51.38121546961326%; + *margin-left: 51.27483249088986%; + } + .row-fluid .offset5 { + margin-left: 45.58011049723757%; + *margin-left: 45.47372751851417%; + } + .row-fluid .offset5:first-child { + margin-left: 42.81767955801105%; + *margin-left: 42.71129657928765%; + } + .row-fluid .offset4 { + margin-left: 37.01657458563536%; + *margin-left: 36.91019160691196%; + } + .row-fluid .offset4:first-child { + margin-left: 34.25414364640884%; + *margin-left: 34.14776066768544%; + } + .row-fluid .offset3 { + margin-left: 28.45303867403315%; + *margin-left: 28.346655695309746%; + } + .row-fluid .offset3:first-child { + margin-left: 25.69060773480663%; + *margin-left: 25.584224756083227%; + } + .row-fluid .offset2 { + margin-left: 19.88950276243094%; + *margin-left: 19.783119783707537%; + } + .row-fluid .offset2:first-child { + margin-left: 17.12707182320442%; + *margin-left: 17.02068884448102%; + } + .row-fluid .offset1 { + margin-left: 11.32596685082873%; + *margin-left: 11.219583872105325%; + } + .row-fluid .offset1:first-child { + margin-left: 8.56353591160221%; + *margin-left: 8.457152932878806%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 710px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 648px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 586px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 524px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 462px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 400px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 338px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 276px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 214px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 152px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 90px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 28px; + } +} + +@media (max-width: 767px) { + body { + padding-right: 20px; + padding-left: 20px; + } + .navbar-fixed-top, + .navbar-fixed-bottom, + .navbar-static-top { + margin-right: -20px; + margin-left: -20px; + } + .container-fluid { + padding: 0; + } + .dl-horizontal dt { + float: none; + width: auto; + clear: none; + text-align: left; + } + .dl-horizontal dd { + margin-left: 0; + } + .container { + width: auto; + } + .row-fluid { + width: 100%; + } + .row, + .thumbnails { + margin-left: 0; + } + .thumbnails > li { + float: none; + margin-left: 0; + } + [class*="span"], + .row-fluid [class*="span"] { + display: block; + float: none; + width: 100%; + margin-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .span12, + .row-fluid .span12 { + width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .input-large, + .input-xlarge, + .input-xxlarge, + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .input-prepend input, + .input-append input, + .input-prepend input[class*="span"], + .input-append input[class*="span"] { + display: inline-block; + width: auto; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 0; + } + .modal { + position: fixed; + top: 20px; + right: 20px; + left: 20px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } +} + +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 20px; + } + input[type="checkbox"], + input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-right: 10px; + padding-left: 10px; + } + .modal { + top: 10px; + right: 10px; + left: 10px; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} + +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top, + .navbar-fixed-bottom { + position: static; + } + .navbar-fixed-top { + margin-bottom: 20px; + } + .navbar-fixed-bottom { + margin-top: 20px; + } + .navbar-fixed-top .navbar-inner, + .navbar-fixed-bottom .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-right: 10px; + padding-left: 10px; + margin: 0 0 0 -5px; + } + .nav-collapse { + clear: both; + } + .nav-collapse .nav { + float: none; + margin: 0 0 10px; + } + .nav-collapse .nav > li { + float: none; + } + .nav-collapse .nav > li > a { + margin-bottom: 2px; + } + .nav-collapse .nav > .divider-vertical { + display: none; + } + .nav-collapse .nav .nav-header { + color: #777777; + text-shadow: none; + } + .nav-collapse .nav > li > a, + .nav-collapse .dropdown-menu a { + padding: 9px 15px; + font-weight: bold; + color: #777777; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .nav-collapse .btn { + padding: 4px 10px 4px; + font-weight: normal; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + } + .nav-collapse .dropdown-menu li + li a { + margin-bottom: 2px; + } + .nav-collapse .nav > li > a:hover, + .nav-collapse .dropdown-menu a:hover { + background-color: #f2f2f2; + } + .navbar-inverse .nav-collapse .nav > li > a:hover, + .navbar-inverse .nav-collapse .dropdown-menu a:hover { + background-color: #111111; + } + .nav-collapse.in .btn-group { + padding: 0; + margin-top: 5px; + } + .nav-collapse .dropdown-menu { + position: static; + top: auto; + left: auto; + display: block; + float: none; + max-width: none; + padding: 0; + margin: 0 15px; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .nav-collapse .dropdown-menu:before, + .nav-collapse .dropdown-menu:after { + display: none; + } + .nav-collapse .dropdown-menu .divider { + display: none; + } + .nav-collapse .nav > li > .dropdown-menu:before, + .nav-collapse .nav > li > .dropdown-menu:after { + display: none; + } + .nav-collapse .navbar-form, + .nav-collapse .navbar-search { + float: none; + padding: 10px 15px; + margin: 10px 0; + border-top: 1px solid #f2f2f2; + border-bottom: 1px solid #f2f2f2; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar-inverse .nav-collapse .navbar-form, + .navbar-inverse .nav-collapse .navbar-search { + border-top-color: #111111; + border-bottom-color: #111111; + } + .navbar .nav-collapse .nav.pull-right { + float: none; + margin-left: 0; + } + .nav-collapse, + .nav-collapse.collapse { + height: 0; + overflow: hidden; + } + .navbar .btn-navbar { + display: block; + } + .navbar-static .navbar-inner { + padding-right: 10px; + padding-left: 10px; + } +} + +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + overflow: visible !important; + } +} diff --git a/docs/public/bootstrap/css/bootstrap-responsive.min.css b/docs/public/bootstrap/css/bootstrap-responsive.min.css new file mode 100644 index 00000000..7b0158da --- /dev/null +++ b/docs/public/bootstrap/css/bootstrap-responsive.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap Responsive v2.1.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade.in{top:auto}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:block;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} diff --git a/docs/public/bootstrap/css/bootstrap.css b/docs/public/bootstrap/css/bootstrap.css new file mode 100644 index 00000000..9fa6f766 --- /dev/null +++ b/docs/public/bootstrap/css/bootstrap.css @@ -0,0 +1,5774 @@ +/*! + * Bootstrap v2.1.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +audio:not([controls]) { + display: none; +} + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +a:hover, +a:active { + outline: 0; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + width: auto\9; + height: auto; + max-width: 100%; + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} + +#map_canvas img { + max-width: none; +} + +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} + +button, +input { + *overflow: visible; + line-height: normal; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} + +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + line-height: 0; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 20px; + color: #333333; + background-color: #ffffff; +} + +a { + color: #0088cc; + text-decoration: none; +} + +a:hover { + color: #005580; + text-decoration: underline; +} + +.img-rounded { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.img-polaroid { + padding: 4px; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +.img-circle { + -webkit-border-radius: 500px; + -moz-border-radius: 500px; + border-radius: 500px; +} + +.row { + margin-left: -20px; + *zoom: 1; +} + +.row:before, +.row:after { + display: table; + line-height: 0; + content: ""; +} + +.row:after { + clear: both; +} + +[class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; +} + +.container, +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.span12 { + width: 940px; +} + +.span11 { + width: 860px; +} + +.span10 { + width: 780px; +} + +.span9 { + width: 700px; +} + +.span8 { + width: 620px; +} + +.span7 { + width: 540px; +} + +.span6 { + width: 460px; +} + +.span5 { + width: 380px; +} + +.span4 { + width: 300px; +} + +.span3 { + width: 220px; +} + +.span2 { + width: 140px; +} + +.span1 { + width: 60px; +} + +.offset12 { + margin-left: 980px; +} + +.offset11 { + margin-left: 900px; +} + +.offset10 { + margin-left: 820px; +} + +.offset9 { + margin-left: 740px; +} + +.offset8 { + margin-left: 660px; +} + +.offset7 { + margin-left: 580px; +} + +.offset6 { + margin-left: 500px; +} + +.offset5 { + margin-left: 420px; +} + +.offset4 { + margin-left: 340px; +} + +.offset3 { + margin-left: 260px; +} + +.offset2 { + margin-left: 180px; +} + +.offset1 { + margin-left: 100px; +} + +.row-fluid { + width: 100%; + *zoom: 1; +} + +.row-fluid:before, +.row-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.row-fluid:after { + clear: both; +} + +.row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.127659574468085%; + *margin-left: 2.074468085106383%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.row-fluid [class*="span"]:first-child { + margin-left: 0; +} + +.row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; +} + +.row-fluid .span11 { + width: 91.48936170212765%; + *width: 91.43617021276594%; +} + +.row-fluid .span10 { + width: 82.97872340425532%; + *width: 82.92553191489361%; +} + +.row-fluid .span9 { + width: 74.46808510638297%; + *width: 74.41489361702126%; +} + +.row-fluid .span8 { + width: 65.95744680851064%; + *width: 65.90425531914893%; +} + +.row-fluid .span7 { + width: 57.44680851063829%; + *width: 57.39361702127659%; +} + +.row-fluid .span6 { + width: 48.93617021276595%; + *width: 48.88297872340425%; +} + +.row-fluid .span5 { + width: 40.42553191489362%; + *width: 40.37234042553192%; +} + +.row-fluid .span4 { + width: 31.914893617021278%; + *width: 31.861702127659576%; +} + +.row-fluid .span3 { + width: 23.404255319148934%; + *width: 23.351063829787233%; +} + +.row-fluid .span2 { + width: 14.893617021276595%; + *width: 14.840425531914894%; +} + +.row-fluid .span1 { + width: 6.382978723404255%; + *width: 6.329787234042553%; +} + +.row-fluid .offset12 { + margin-left: 104.25531914893617%; + *margin-left: 104.14893617021275%; +} + +.row-fluid .offset12:first-child { + margin-left: 102.12765957446808%; + *margin-left: 102.02127659574467%; +} + +.row-fluid .offset11 { + margin-left: 95.74468085106382%; + *margin-left: 95.6382978723404%; +} + +.row-fluid .offset11:first-child { + margin-left: 93.61702127659574%; + *margin-left: 93.51063829787232%; +} + +.row-fluid .offset10 { + margin-left: 87.23404255319149%; + *margin-left: 87.12765957446807%; +} + +.row-fluid .offset10:first-child { + margin-left: 85.1063829787234%; + *margin-left: 84.99999999999999%; +} + +.row-fluid .offset9 { + margin-left: 78.72340425531914%; + *margin-left: 78.61702127659572%; +} + +.row-fluid .offset9:first-child { + margin-left: 76.59574468085106%; + *margin-left: 76.48936170212764%; +} + +.row-fluid .offset8 { + margin-left: 70.2127659574468%; + *margin-left: 70.10638297872339%; +} + +.row-fluid .offset8:first-child { + margin-left: 68.08510638297872%; + *margin-left: 67.9787234042553%; +} + +.row-fluid .offset7 { + margin-left: 61.70212765957446%; + *margin-left: 61.59574468085106%; +} + +.row-fluid .offset7:first-child { + margin-left: 59.574468085106375%; + *margin-left: 59.46808510638297%; +} + +.row-fluid .offset6 { + margin-left: 53.191489361702125%; + *margin-left: 53.085106382978715%; +} + +.row-fluid .offset6:first-child { + margin-left: 51.063829787234035%; + *margin-left: 50.95744680851063%; +} + +.row-fluid .offset5 { + margin-left: 44.68085106382979%; + *margin-left: 44.57446808510638%; +} + +.row-fluid .offset5:first-child { + margin-left: 42.5531914893617%; + *margin-left: 42.4468085106383%; +} + +.row-fluid .offset4 { + margin-left: 36.170212765957444%; + *margin-left: 36.06382978723405%; +} + +.row-fluid .offset4:first-child { + margin-left: 34.04255319148936%; + *margin-left: 33.93617021276596%; +} + +.row-fluid .offset3 { + margin-left: 27.659574468085104%; + *margin-left: 27.5531914893617%; +} + +.row-fluid .offset3:first-child { + margin-left: 25.53191489361702%; + *margin-left: 25.425531914893618%; +} + +.row-fluid .offset2 { + margin-left: 19.148936170212764%; + *margin-left: 19.04255319148936%; +} + +.row-fluid .offset2:first-child { + margin-left: 17.02127659574468%; + *margin-left: 16.914893617021278%; +} + +.row-fluid .offset1 { + margin-left: 10.638297872340425%; + *margin-left: 10.53191489361702%; +} + +.row-fluid .offset1:first-child { + margin-left: 8.51063829787234%; + *margin-left: 8.404255319148938%; +} + +[class*="span"].hide, +.row-fluid [class*="span"].hide { + display: none; +} + +[class*="span"].pull-right, +.row-fluid [class*="span"].pull-right { + float: right; +} + +.container { + margin-right: auto; + margin-left: auto; + *zoom: 1; +} + +.container:before, +.container:after { + display: table; + line-height: 0; + content: ""; +} + +.container:after { + clear: both; +} + +.container-fluid { + padding-right: 20px; + padding-left: 20px; + *zoom: 1; +} + +.container-fluid:before, +.container-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.container-fluid:after { + clear: both; +} + +p { + margin: 0 0 10px; +} + +.lead { + margin-bottom: 20px; + font-size: 21px; + font-weight: 200; + line-height: 30px; +} + +small { + font-size: 85%; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +cite { + font-style: normal; +} + +.muted { + color: #999999; +} + +.text-warning { + color: #c09853; +} + +.text-error { + color: #b94a48; +} + +.text-info { + color: #3a87ad; +} + +.text-success { + color: #468847; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 10px 0; + font-family: inherit; + font-weight: bold; + line-height: 1; + color: inherit; + text-rendering: optimizelegibility; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + line-height: 1; + color: #999999; +} + +h1 { + font-size: 36px; + line-height: 40px; +} + +h2 { + font-size: 30px; + line-height: 40px; +} + +h3 { + font-size: 24px; + line-height: 40px; +} + +h4 { + font-size: 18px; + line-height: 20px; +} + +h5 { + font-size: 14px; + line-height: 20px; +} + +h6 { + font-size: 12px; + line-height: 20px; +} + +h1 small { + font-size: 24px; +} + +h2 small { + font-size: 18px; +} + +h3 small { + font-size: 14px; +} + +h4 small { + font-size: 14px; +} + +.page-header { + padding-bottom: 9px; + margin: 20px 0 30px; + border-bottom: 1px solid #eeeeee; +} + +ul, +ol { + padding: 0; + margin: 0 0 10px 25px; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} + +li { + line-height: 20px; +} + +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} + +dl { + margin-bottom: 20px; +} + +dt, +dd { + line-height: 20px; +} + +dt { + font-weight: bold; +} + +dd { + margin-left: 10px; +} + +.dl-horizontal { + *zoom: 1; +} + +.dl-horizontal:before, +.dl-horizontal:after { + display: table; + line-height: 0; + content: ""; +} + +.dl-horizontal:after { + clear: both; +} + +.dl-horizontal dt { + float: left; + width: 160px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dl-horizontal dd { + margin-left: 180px; +} + +hr { + margin: 20px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} + +abbr[title] { + cursor: help; + border-bottom: 1px dotted #999999; +} + +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 0 0 0 15px; + margin: 0 0 20px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 25px; +} + +blockquote small { + display: block; + line-height: 20px; + color: #999999; +} + +blockquote small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small { + text-align: right; +} + +blockquote.pull-right small:before { + content: ''; +} + +blockquote.pull-right small:after { + content: '\00A0 \2014'; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +address { + display: block; + margin-bottom: 20px; + font-style: normal; + line-height: 20px; +} + +code, +pre { + padding: 0 3px 2px; + font-family: Monaco, Menlo, Consolas, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +code { + padding: 2px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} + +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 20px; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +pre.prettyprint { + margin-bottom: 20px; +} + +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +form { + margin: 0 0 20px; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: 40px; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} + +legend small { + font-size: 15px; + color: #999999; +} + +label, +input, +button, +select, +textarea { + font-size: 14px; + font-weight: normal; + line-height: 20px; +} + +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +label { + display: block; + margin-bottom: 5px; +} + +select, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + display: inline-block; + height: 20px; + padding: 4px 6px; + margin-bottom: 9px; + font-size: 14px; + line-height: 20px; + color: #555555; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +input, +textarea, +.uneditable-input { + width: 206px; +} + +textarea { + height: auto; +} + +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + background-color: #ffffff; + border: 1px solid #cccccc; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} + +textarea:focus, +input[type="text"]:focus, +input[type="password"]:focus, +input[type="datetime"]:focus, +input[type="datetime-local"]:focus, +input[type="date"]:focus, +input[type="month"]:focus, +input[type="time"]:focus, +input[type="week"]:focus, +input[type="number"]:focus, +input[type="email"]:focus, +input[type="url"]:focus, +input[type="search"]:focus, +input[type="tel"]:focus, +input[type="color"]:focus, +.uneditable-input:focus { + border-color: rgba(82, 168, 236, 0.8); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); +} + +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + *margin-top: 0; + line-height: normal; + cursor: pointer; +} + +input[type="file"], +input[type="image"], +input[type="submit"], +input[type="reset"], +input[type="button"], +input[type="radio"], +input[type="checkbox"] { + width: auto; +} + +select, +input[type="file"] { + height: 30px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 30px; +} + +select { + width: 220px; + background-color: #ffffff; + border: 1px solid #cccccc; +} + +select[multiple], +select[size] { + height: auto; +} + +select:focus, +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.uneditable-input, +.uneditable-textarea { + color: #999999; + cursor: not-allowed; + background-color: #fcfcfc; + border-color: #cccccc; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); +} + +.uneditable-input { + overflow: hidden; + white-space: nowrap; +} + +.uneditable-textarea { + width: auto; + height: auto; +} + +input:-moz-placeholder, +textarea:-moz-placeholder { + color: #999999; +} + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #999999; +} + +input::-webkit-input-placeholder, +textarea::-webkit-input-placeholder { + color: #999999; +} + +.radio, +.checkbox { + min-height: 18px; + padding-left: 18px; +} + +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} + +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; +} + +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} + +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; +} + +.input-mini { + width: 60px; +} + +.input-small { + width: 90px; +} + +.input-medium { + width: 150px; +} + +.input-large { + width: 210px; +} + +.input-xlarge { + width: 270px; +} + +.input-xxlarge { + width: 530px; +} + +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"] { + float: none; + margin-left: 0; +} + +.input-append input[class*="span"], +.input-append .uneditable-input[class*="span"], +.input-prepend input[class*="span"], +.input-prepend .uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"], +.row-fluid .input-prepend [class*="span"], +.row-fluid .input-append [class*="span"] { + display: inline-block; +} + +input, +textarea, +.uneditable-input { + margin-left: 0; +} + +.controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; +} + +input.span12, +textarea.span12, +.uneditable-input.span12 { + width: 926px; +} + +input.span11, +textarea.span11, +.uneditable-input.span11 { + width: 846px; +} + +input.span10, +textarea.span10, +.uneditable-input.span10 { + width: 766px; +} + +input.span9, +textarea.span9, +.uneditable-input.span9 { + width: 686px; +} + +input.span8, +textarea.span8, +.uneditable-input.span8 { + width: 606px; +} + +input.span7, +textarea.span7, +.uneditable-input.span7 { + width: 526px; +} + +input.span6, +textarea.span6, +.uneditable-input.span6 { + width: 446px; +} + +input.span5, +textarea.span5, +.uneditable-input.span5 { + width: 366px; +} + +input.span4, +textarea.span4, +.uneditable-input.span4 { + width: 286px; +} + +input.span3, +textarea.span3, +.uneditable-input.span3 { + width: 206px; +} + +input.span2, +textarea.span2, +.uneditable-input.span2 { + width: 126px; +} + +input.span1, +textarea.span1, +.uneditable-input.span1 { + width: 46px; +} + +.controls-row { + *zoom: 1; +} + +.controls-row:before, +.controls-row:after { + display: table; + line-height: 0; + content: ""; +} + +.controls-row:after { + clear: both; +} + +.controls-row [class*="span"] { + float: left; +} + +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: #eeeeee; +} + +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"][readonly], +input[type="checkbox"][readonly] { + background-color: transparent; +} + +.control-group.warning > label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #c09853; +} + +.control-group.warning .checkbox, +.control-group.warning .radio, +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #c09853; +} + +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + border-color: #c09853; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; +} + +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} + +.control-group.error > label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #b94a48; +} + +.control-group.error .checkbox, +.control-group.error .radio, +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #b94a48; +} + +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + border-color: #b94a48; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; +} + +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} + +.control-group.success > label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #468847; +} + +.control-group.success .checkbox, +.control-group.success .radio, +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #468847; +} + +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + border-color: #468847; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; +} + +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} + +.control-group.info > label, +.control-group.info .help-block, +.control-group.info .help-inline { + color: #3a87ad; +} + +.control-group.info .checkbox, +.control-group.info .radio, +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + color: #3a87ad; +} + +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + border-color: #3a87ad; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.info input:focus, +.control-group.info select:focus, +.control-group.info textarea:focus { + border-color: #2d6987; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; +} + +.control-group.info .input-prepend .add-on, +.control-group.info .input-append .add-on { + color: #3a87ad; + background-color: #d9edf7; + border-color: #3a87ad; +} + +input:focus:required:invalid, +textarea:focus:required:invalid, +select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} + +input:focus:required:invalid:focus, +textarea:focus:required:invalid:focus, +select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} + +.form-actions { + padding: 19px 20px 20px; + margin-top: 20px; + margin-bottom: 20px; + background-color: #f5f5f5; + border-top: 1px solid #e5e5e5; + *zoom: 1; +} + +.form-actions:before, +.form-actions:after { + display: table; + line-height: 0; + content: ""; +} + +.form-actions:after { + clear: both; +} + +.help-block, +.help-inline { + color: #595959; +} + +.help-block { + display: block; + margin-bottom: 10px; +} + +.help-inline { + display: inline-block; + *display: inline; + padding-left: 5px; + vertical-align: middle; + *zoom: 1; +} + +.input-append, +.input-prepend { + margin-bottom: 5px; + font-size: 0; + white-space: nowrap; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input { + position: relative; + margin-bottom: 0; + *margin-left: 0; + font-size: 14px; + vertical-align: top; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.input-append input:focus, +.input-prepend input:focus, +.input-append select:focus, +.input-prepend select:focus, +.input-append .uneditable-input:focus, +.input-prepend .uneditable-input:focus { + z-index: 2; +} + +.input-append .add-on, +.input-prepend .add-on { + display: inline-block; + width: auto; + height: 20px; + min-width: 16px; + padding: 4px 5px; + font-size: 14px; + font-weight: normal; + line-height: 20px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #eeeeee; + border: 1px solid #ccc; +} + +.input-append .add-on, +.input-prepend .add-on, +.input-append .btn, +.input-prepend .btn { + vertical-align: top; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-append .active, +.input-prepend .active { + background-color: #a9dba9; + border-color: #46a546; +} + +.input-prepend .add-on, +.input-prepend .btn { + margin-right: -1px; +} + +.input-prepend .add-on:first-child, +.input-prepend .btn:first-child { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-append input, +.input-append select, +.input-append .uneditable-input { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-append .add-on, +.input-append .btn { + margin-left: -1px; +} + +.input-append .add-on:last-child, +.input-append .btn:last-child { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.input-prepend.input-append input, +.input-prepend.input-append select, +.input-prepend.input-append .uneditable-input { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend.input-append .add-on:first-child, +.input-prepend.input-append .btn:first-child { + margin-right: -1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-prepend.input-append .add-on:last-child, +.input-prepend.input-append .btn:last-child { + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +input.search-query { + padding-right: 14px; + padding-right: 4px \9; + padding-left: 14px; + padding-left: 4px \9; + /* IE7-8 doesn't have border-radius, so don't indent the padding */ + + margin-bottom: 0; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +/* Allow for input prepend/append in search forms */ + +.form-search .input-append .search-query, +.form-search .input-prepend .search-query { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.form-search .input-append .search-query { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search .input-append .btn { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .search-query { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .btn { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input, +.form-search .input-prepend, +.form-inline .input-prepend, +.form-horizontal .input-prepend, +.form-search .input-append, +.form-inline .input-append, +.form-horizontal .input-append { + display: inline-block; + *display: inline; + margin-bottom: 0; + vertical-align: middle; + *zoom: 1; +} + +.form-search .hide, +.form-inline .hide, +.form-horizontal .hide { + display: none; +} + +.form-search label, +.form-inline label, +.form-search .btn-group, +.form-inline .btn-group { + display: inline-block; +} + +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} + +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} + +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} + +.control-group { + margin-bottom: 10px; +} + +legend + .control-group { + margin-top: 20px; + -webkit-margin-top-collapse: separate; +} + +.form-horizontal .control-group { + margin-bottom: 20px; + *zoom: 1; +} + +.form-horizontal .control-group:before, +.form-horizontal .control-group:after { + display: table; + line-height: 0; + content: ""; +} + +.form-horizontal .control-group:after { + clear: both; +} + +.form-horizontal .control-label { + float: left; + width: 160px; + padding-top: 5px; + text-align: right; +} + +.form-horizontal .controls { + *display: inline-block; + *padding-left: 20px; + margin-left: 180px; + *margin-left: 0; +} + +.form-horizontal .controls:first-child { + *padding-left: 180px; +} + +.form-horizontal .help-block { + margin-bottom: 0; +} + +.form-horizontal input + .help-block, +.form-horizontal select + .help-block, +.form-horizontal textarea + .help-block { + margin-top: 10px; +} + +.form-horizontal .form-actions { + padding-left: 180px; +} + +table { + max-width: 100%; + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} + +.table { + width: 100%; + margin-bottom: 20px; +} + +.table th, +.table td { + padding: 8px; + line-height: 20px; + text-align: left; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table th { + font-weight: bold; +} + +.table thead th { + vertical-align: bottom; +} + +.table caption + thead tr:first-child th, +.table caption + thead tr:first-child td, +.table colgroup + thead tr:first-child th, +.table colgroup + thead tr:first-child td, +.table thead:first-child tr:first-child th, +.table thead:first-child tr:first-child td { + border-top: 0; +} + +.table tbody + tbody { + border-top: 2px solid #dddddd; +} + +.table-condensed th, +.table-condensed td { + padding: 4px 5px; +} + +.table-bordered { + border: 1px solid #dddddd; + border-collapse: separate; + *border-collapse: collapse; + border-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.table-bordered th, +.table-bordered td { + border-left: 1px solid #dddddd; +} + +.table-bordered caption + thead tr:first-child th, +.table-bordered caption + tbody tr:first-child th, +.table-bordered caption + tbody tr:first-child td, +.table-bordered colgroup + thead tr:first-child th, +.table-bordered colgroup + tbody tr:first-child th, +.table-bordered colgroup + tbody tr:first-child td, +.table-bordered thead:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} + +.table-bordered thead:first-child tr:first-child th:first-child, +.table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered thead:first-child tr:first-child th:last-child, +.table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-bordered thead:last-child tr:last-child th:first-child, +.table-bordered tbody:last-child tr:last-child td:first-child, +.table-bordered tfoot:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.table-bordered thead:last-child tr:last-child th:last-child, +.table-bordered tbody:last-child tr:last-child td:last-child, +.table-bordered tfoot:last-child tr:last-child td:last-child { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; +} + +.table-bordered caption + thead tr:first-child th:first-child, +.table-bordered caption + tbody tr:first-child td:first-child, +.table-bordered colgroup + thead tr:first-child th:first-child, +.table-bordered colgroup + tbody tr:first-child td:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered caption + thead tr:first-child th:last-child, +.table-bordered caption + tbody tr:first-child td:last-child, +.table-bordered colgroup + thead tr:first-child th:last-child, +.table-bordered colgroup + tbody tr:first-child td:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-striped tbody tr:nth-child(odd) td, +.table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} + +.table-hover tbody tr:hover td, +.table-hover tbody tr:hover th { + background-color: #f5f5f5; +} + +table [class*=span], +.row-fluid table [class*=span] { + display: table-cell; + float: none; + margin-left: 0; +} + +.table .span1 { + float: none; + width: 44px; + margin-left: 0; +} + +.table .span2 { + float: none; + width: 124px; + margin-left: 0; +} + +.table .span3 { + float: none; + width: 204px; + margin-left: 0; +} + +.table .span4 { + float: none; + width: 284px; + margin-left: 0; +} + +.table .span5 { + float: none; + width: 364px; + margin-left: 0; +} + +.table .span6 { + float: none; + width: 444px; + margin-left: 0; +} + +.table .span7 { + float: none; + width: 524px; + margin-left: 0; +} + +.table .span8 { + float: none; + width: 604px; + margin-left: 0; +} + +.table .span9 { + float: none; + width: 684px; + margin-left: 0; +} + +.table .span10 { + float: none; + width: 764px; + margin-left: 0; +} + +.table .span11 { + float: none; + width: 844px; + margin-left: 0; +} + +.table .span12 { + float: none; + width: 924px; + margin-left: 0; +} + +.table .span13 { + float: none; + width: 1004px; + margin-left: 0; +} + +.table .span14 { + float: none; + width: 1084px; + margin-left: 0; +} + +.table .span15 { + float: none; + width: 1164px; + margin-left: 0; +} + +.table .span16 { + float: none; + width: 1244px; + margin-left: 0; +} + +.table .span17 { + float: none; + width: 1324px; + margin-left: 0; +} + +.table .span18 { + float: none; + width: 1404px; + margin-left: 0; +} + +.table .span19 { + float: none; + width: 1484px; + margin-left: 0; +} + +.table .span20 { + float: none; + width: 1564px; + margin-left: 0; +} + +.table .span21 { + float: none; + width: 1644px; + margin-left: 0; +} + +.table .span22 { + float: none; + width: 1724px; + margin-left: 0; +} + +.table .span23 { + float: none; + width: 1804px; + margin-left: 0; +} + +.table .span24 { + float: none; + width: 1884px; + margin-left: 0; +} + +.table tbody tr.success td { + background-color: #dff0d8; +} + +.table tbody tr.error td { + background-color: #f2dede; +} + +.table tbody tr.warning td { + background-color: #fcf8e3; +} + +.table tbody tr.info td { + background-color: #d9edf7; +} + +.table-hover tbody tr.success:hover td { + background-color: #d0e9c6; +} + +.table-hover tbody tr.error:hover td { + background-color: #ebcccc; +} + +.table-hover tbody tr.warning:hover td { + background-color: #faf2cc; +} + +.table-hover tbody tr.info:hover td { + background-color: #c4e3f3; +} + +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + margin-top: 1px; + *margin-right: .3em; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; +} + +/* White icons with optional class, or on hover/active states of certain elements */ + +.icon-white, +.nav-tabs > .active > a > [class^="icon-"], +.nav-tabs > .active > a > [class*=" icon-"], +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"] { + background-image: url("../img/glyphicons-halflings-white.png"); +} + +.icon-glass { + background-position: 0 0; +} + +.icon-music { + background-position: -24px 0; +} + +.icon-search { + background-position: -48px 0; +} + +.icon-envelope { + background-position: -72px 0; +} + +.icon-heart { + background-position: -96px 0; +} + +.icon-star { + background-position: -120px 0; +} + +.icon-star-empty { + background-position: -144px 0; +} + +.icon-user { + background-position: -168px 0; +} + +.icon-film { + background-position: -192px 0; +} + +.icon-th-large { + background-position: -216px 0; +} + +.icon-th { + background-position: -240px 0; +} + +.icon-th-list { + background-position: -264px 0; +} + +.icon-ok { + background-position: -288px 0; +} + +.icon-remove { + background-position: -312px 0; +} + +.icon-zoom-in { + background-position: -336px 0; +} + +.icon-zoom-out { + background-position: -360px 0; +} + +.icon-off { + background-position: -384px 0; +} + +.icon-signal { + background-position: -408px 0; +} + +.icon-cog { + background-position: -432px 0; +} + +.icon-trash { + background-position: -456px 0; +} + +.icon-home { + background-position: 0 -24px; +} + +.icon-file { + background-position: -24px -24px; +} + +.icon-time { + background-position: -48px -24px; +} + +.icon-road { + background-position: -72px -24px; +} + +.icon-download-alt { + background-position: -96px -24px; +} + +.icon-download { + background-position: -120px -24px; +} + +.icon-upload { + background-position: -144px -24px; +} + +.icon-inbox { + background-position: -168px -24px; +} + +.icon-play-circle { + background-position: -192px -24px; +} + +.icon-repeat { + background-position: -216px -24px; +} + +.icon-refresh { + background-position: -240px -24px; +} + +.icon-list-alt { + background-position: -264px -24px; +} + +.icon-lock { + background-position: -287px -24px; +} + +.icon-flag { + background-position: -312px -24px; +} + +.icon-headphones { + background-position: -336px -24px; +} + +.icon-volume-off { + background-position: -360px -24px; +} + +.icon-volume-down { + background-position: -384px -24px; +} + +.icon-volume-up { + background-position: -408px -24px; +} + +.icon-qrcode { + background-position: -432px -24px; +} + +.icon-barcode { + background-position: -456px -24px; +} + +.icon-tag { + background-position: 0 -48px; +} + +.icon-tags { + background-position: -25px -48px; +} + +.icon-book { + background-position: -48px -48px; +} + +.icon-bookmark { + background-position: -72px -48px; +} + +.icon-print { + background-position: -96px -48px; +} + +.icon-camera { + background-position: -120px -48px; +} + +.icon-font { + background-position: -144px -48px; +} + +.icon-bold { + background-position: -167px -48px; +} + +.icon-italic { + background-position: -192px -48px; +} + +.icon-text-height { + background-position: -216px -48px; +} + +.icon-text-width { + background-position: -240px -48px; +} + +.icon-align-left { + background-position: -264px -48px; +} + +.icon-align-center { + background-position: -288px -48px; +} + +.icon-align-right { + background-position: -312px -48px; +} + +.icon-align-justify { + background-position: -336px -48px; +} + +.icon-list { + background-position: -360px -48px; +} + +.icon-indent-left { + background-position: -384px -48px; +} + +.icon-indent-right { + background-position: -408px -48px; +} + +.icon-facetime-video { + background-position: -432px -48px; +} + +.icon-picture { + background-position: -456px -48px; +} + +.icon-pencil { + background-position: 0 -72px; +} + +.icon-map-marker { + background-position: -24px -72px; +} + +.icon-adjust { + background-position: -48px -72px; +} + +.icon-tint { + background-position: -72px -72px; +} + +.icon-edit { + background-position: -96px -72px; +} + +.icon-share { + background-position: -120px -72px; +} + +.icon-check { + background-position: -144px -72px; +} + +.icon-move { + background-position: -168px -72px; +} + +.icon-step-backward { + background-position: -192px -72px; +} + +.icon-fast-backward { + background-position: -216px -72px; +} + +.icon-backward { + background-position: -240px -72px; +} + +.icon-play { + background-position: -264px -72px; +} + +.icon-pause { + background-position: -288px -72px; +} + +.icon-stop { + background-position: -312px -72px; +} + +.icon-forward { + background-position: -336px -72px; +} + +.icon-fast-forward { + background-position: -360px -72px; +} + +.icon-step-forward { + background-position: -384px -72px; +} + +.icon-eject { + background-position: -408px -72px; +} + +.icon-chevron-left { + background-position: -432px -72px; +} + +.icon-chevron-right { + background-position: -456px -72px; +} + +.icon-plus-sign { + background-position: 0 -96px; +} + +.icon-minus-sign { + background-position: -24px -96px; +} + +.icon-remove-sign { + background-position: -48px -96px; +} + +.icon-ok-sign { + background-position: -72px -96px; +} + +.icon-question-sign { + background-position: -96px -96px; +} + +.icon-info-sign { + background-position: -120px -96px; +} + +.icon-screenshot { + background-position: -144px -96px; +} + +.icon-remove-circle { + background-position: -168px -96px; +} + +.icon-ok-circle { + background-position: -192px -96px; +} + +.icon-ban-circle { + background-position: -216px -96px; +} + +.icon-arrow-left { + background-position: -240px -96px; +} + +.icon-arrow-right { + background-position: -264px -96px; +} + +.icon-arrow-up { + background-position: -289px -96px; +} + +.icon-arrow-down { + background-position: -312px -96px; +} + +.icon-share-alt { + background-position: -336px -96px; +} + +.icon-resize-full { + background-position: -360px -96px; +} + +.icon-resize-small { + background-position: -384px -96px; +} + +.icon-plus { + background-position: -408px -96px; +} + +.icon-minus { + background-position: -433px -96px; +} + +.icon-asterisk { + background-position: -456px -96px; +} + +.icon-exclamation-sign { + background-position: 0 -120px; +} + +.icon-gift { + background-position: -24px -120px; +} + +.icon-leaf { + background-position: -48px -120px; +} + +.icon-fire { + background-position: -72px -120px; +} + +.icon-eye-open { + background-position: -96px -120px; +} + +.icon-eye-close { + background-position: -120px -120px; +} + +.icon-warning-sign { + background-position: -144px -120px; +} + +.icon-plane { + background-position: -168px -120px; +} + +.icon-calendar { + background-position: -192px -120px; +} + +.icon-random { + width: 16px; + background-position: -216px -120px; +} + +.icon-comment { + background-position: -240px -120px; +} + +.icon-magnet { + background-position: -264px -120px; +} + +.icon-chevron-up { + background-position: -288px -120px; +} + +.icon-chevron-down { + background-position: -313px -119px; +} + +.icon-retweet { + background-position: -336px -120px; +} + +.icon-shopping-cart { + background-position: -360px -120px; +} + +.icon-folder-close { + background-position: -384px -120px; +} + +.icon-folder-open { + width: 16px; + background-position: -408px -120px; +} + +.icon-resize-vertical { + background-position: -432px -119px; +} + +.icon-resize-horizontal { + background-position: -456px -118px; +} + +.icon-hdd { + background-position: 0 -144px; +} + +.icon-bullhorn { + background-position: -24px -144px; +} + +.icon-bell { + background-position: -48px -144px; +} + +.icon-certificate { + background-position: -72px -144px; +} + +.icon-thumbs-up { + background-position: -96px -144px; +} + +.icon-thumbs-down { + background-position: -120px -144px; +} + +.icon-hand-right { + background-position: -144px -144px; +} + +.icon-hand-left { + background-position: -168px -144px; +} + +.icon-hand-up { + background-position: -192px -144px; +} + +.icon-hand-down { + background-position: -216px -144px; +} + +.icon-circle-arrow-right { + background-position: -240px -144px; +} + +.icon-circle-arrow-left { + background-position: -264px -144px; +} + +.icon-circle-arrow-up { + background-position: -288px -144px; +} + +.icon-circle-arrow-down { + background-position: -312px -144px; +} + +.icon-globe { + background-position: -336px -144px; +} + +.icon-wrench { + background-position: -360px -144px; +} + +.icon-tasks { + background-position: -384px -144px; +} + +.icon-filter { + background-position: -408px -144px; +} + +.icon-briefcase { + background-position: -432px -144px; +} + +.icon-fullscreen { + background-position: -456px -144px; +} + +.dropup, +.dropdown { + position: relative; +} + +.dropdown-toggle { + *margin-bottom: -3px; +} + +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} + +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; +} + +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.dropdown-menu .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.dropdown-menu a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 20px; + color: #333333; + white-space: nowrap; +} + +.dropdown-menu li > a:hover, +.dropdown-menu li > a:focus, +.dropdown-submenu:hover > a { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} + +.dropdown-menu .active > a, +.dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; + background-color: #0081c2; + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-repeat: repeat-x; + outline: 0; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} + +.dropdown-menu .disabled > a, +.dropdown-menu .disabled > a:hover { + color: #999999; +} + +.dropdown-menu .disabled > a:hover { + text-decoration: none; + cursor: default; + background-color: transparent; +} + +.open { + *z-index: 1000; +} + +.open > .dropdown-menu { + display: block; +} + +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid #000000; + content: ""; +} + +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} + +.dropdown-submenu { + position: relative; +} + +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + -webkit-border-radius: 0 6px 6px 6px; + -moz-border-radius: 0 6px 6px 6px; + border-radius: 0 6px 6px 6px; +} + +.dropdown-submenu:hover > .dropdown-menu { + display: block; +} + +.dropdown-submenu > a:after { + display: block; + float: right; + width: 0; + height: 0; + margin-top: 5px; + margin-right: -10px; + border-color: transparent; + border-left-color: #cccccc; + border-style: solid; + border-width: 5px 0 5px 5px; + content: " "; +} + +.dropdown-submenu:hover > a:after { + border-left-color: #ffffff; +} + +.dropdown .dropdown-menu .nav-header { + padding-right: 20px; + padding-left: 20px; +} + +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} + +.well-large { + padding: 24px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.well-small { + padding: 9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +.collapse.in { + height: auto; +} + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 20px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + filter: alpha(opacity=40); +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} + +.btn { + display: inline-block; + *display: inline; + padding: 4px 14px; + margin-bottom: 0; + *margin-left: .3em; + font-size: 14px; + line-height: 20px; + *line-height: 20px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + cursor: pointer; + background-color: #f5f5f5; + *background-color: #e6e6e6; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + border: 1px solid #bbbbbb; + *border: 0; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-bottom-color: #a2a2a2; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + color: #333333; + background-color: #e6e6e6; + *background-color: #d9d9d9; +} + +.btn:active, +.btn.active { + background-color: #cccccc \9; +} + +.btn:first-child { + *margin-left: 0; +} + +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + *background-color: #d9d9d9; + /* Buttons in IE7 don't get borders, so darken on hover */ + + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} + +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn.active, +.btn:active { + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled, +.btn[disabled] { + cursor: default; + background-color: #e6e6e6; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-large { + padding: 9px 14px; + font-size: 16px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.btn-large [class^="icon-"] { + margin-top: 2px; +} + +.btn-small { + padding: 3px 9px; + font-size: 12px; + line-height: 18px; +} + +.btn-small [class^="icon-"] { + margin-top: 0; +} + +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 17px; +} + +.btn-block { + display: block; + width: 100%; + padding-right: 0; + padding-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.btn-block + .btn-block { + margin-top: 5px; +} + +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255, 255, 255, 0.75); +} + +.btn { + border-color: #c5c5c5; + border-color: rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25); +} + +.btn-primary { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #006dcc; + *background-color: #0044cc; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(to bottom, #0088cc, #0044cc); + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + color: #ffffff; + background-color: #0044cc; + *background-color: #003bb3; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #003399 \9; +} + +.btn-warning { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #faa732; + *background-color: #f89406; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + color: #ffffff; + background-color: #f89406; + *background-color: #df8505; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} + +.btn-danger { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #da4f49; + *background-color: #bd362f; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(to bottom, #ee5f5b, #bd362f); + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + color: #ffffff; + background-color: #bd362f; + *background-color: #a9302a; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} + +.btn-success { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #5bb75b; + *background-color: #51a351; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(to bottom, #62c462, #51a351); + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + color: #ffffff; + background-color: #51a351; + *background-color: #499249; +} + +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} + +.btn-info { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #49afcd; + *background-color: #2f96b4; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(to bottom, #5bc0de, #2f96b4); + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + color: #ffffff; + background-color: #2f96b4; + *background-color: #2a85a0; +} + +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} + +.btn-inverse { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #363636; + *background-color: #222222; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); + background-image: -webkit-linear-gradient(top, #444444, #222222); + background-image: -o-linear-gradient(top, #444444, #222222); + background-image: linear-gradient(to bottom, #444444, #222222); + background-image: -moz-linear-gradient(top, #444444, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + color: #ffffff; + background-color: #222222; + *background-color: #151515; +} + +.btn-inverse:active, +.btn-inverse.active { + background-color: #080808 \9; +} + +button.btn, +input[type="submit"].btn { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn::-moz-focus-inner, +input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +button.btn.btn-large, +input[type="submit"].btn.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; +} + +button.btn.btn-small, +input[type="submit"].btn.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn.btn-mini, +input[type="submit"].btn.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; +} + +.btn-link, +.btn-link:active, +.btn-link[disabled] { + background-color: transparent; + background-image: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-link { + color: #0088cc; + cursor: pointer; + border-color: transparent; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-link:hover { + color: #005580; + text-decoration: underline; + background-color: transparent; +} + +.btn-link[disabled]:hover { + color: #333333; + text-decoration: none; +} + +.btn-group { + position: relative; + *margin-left: .3em; + font-size: 0; + white-space: nowrap; + vertical-align: middle; +} + +.btn-group:first-child { + *margin-left: 0; +} + +.btn-group + .btn-group { + margin-left: 5px; +} + +.btn-toolbar { + margin-top: 10px; + margin-bottom: 10px; + font-size: 0; +} + +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} + +.btn-toolbar .btn + .btn, +.btn-toolbar .btn-group + .btn, +.btn-toolbar .btn + .btn-group { + margin-left: 5px; +} + +.btn-group > .btn { + position: relative; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group > .btn + .btn { + margin-left: -1px; +} + +.btn-group > .btn, +.btn-group > .dropdown-menu { + font-size: 14px; +} + +.btn-group > .btn-mini { + font-size: 11px; +} + +.btn-group > .btn-small { + font-size: 12px; +} + +.btn-group > .btn-large { + font-size: 16px; +} + +.btn-group > .btn:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.btn-group > .btn:last-child, +.btn-group > .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.btn-group > .btn.large:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.btn-group > .btn.large:last-child, +.btn-group > .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active { + z-index: 2; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group > .btn + .dropdown-toggle { + *padding-top: 5px; + padding-right: 8px; + *padding-bottom: 5px; + padding-left: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group > .btn-mini + .dropdown-toggle { + *padding-top: 2px; + padding-right: 5px; + *padding-bottom: 2px; + padding-left: 5px; +} + +.btn-group > .btn-small + .dropdown-toggle { + *padding-top: 5px; + *padding-bottom: 4px; +} + +.btn-group > .btn-large + .dropdown-toggle { + *padding-top: 7px; + padding-right: 12px; + *padding-bottom: 7px; + padding-left: 12px; +} + +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group.open .btn.dropdown-toggle { + background-color: #e6e6e6; +} + +.btn-group.open .btn-primary.dropdown-toggle { + background-color: #0044cc; +} + +.btn-group.open .btn-warning.dropdown-toggle { + background-color: #f89406; +} + +.btn-group.open .btn-danger.dropdown-toggle { + background-color: #bd362f; +} + +.btn-group.open .btn-success.dropdown-toggle { + background-color: #51a351; +} + +.btn-group.open .btn-info.dropdown-toggle { + background-color: #2f96b4; +} + +.btn-group.open .btn-inverse.dropdown-toggle { + background-color: #222222; +} + +.btn .caret { + margin-top: 8px; + margin-left: 0; +} + +.btn-mini .caret, +.btn-small .caret, +.btn-large .caret { + margin-top: 6px; +} + +.btn-large .caret { + border-top-width: 5px; + border-right-width: 5px; + border-left-width: 5px; +} + +.dropup .btn-large .caret { + border-top: 0; + border-bottom: 5px solid #000000; +} + +.btn-primary .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.btn-group-vertical { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} + +.btn-group-vertical .btn { + display: block; + float: none; + width: 100%; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group-vertical .btn + .btn { + margin-top: -1px; + margin-left: 0; +} + +.btn-group-vertical .btn:first-child { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.btn-group-vertical .btn:last-child { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.btn-group-vertical .btn-large:first-child { + -webkit-border-radius: 6px 6px 0 0; + -moz-border-radius: 6px 6px 0 0; + border-radius: 6px 6px 0 0; +} + +.btn-group-vertical .btn-large:last-child { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 20px; + color: #c09853; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.alert h4 { + margin: 0; +} + +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 20px; +} + +.alert-success { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.alert-danger, +.alert-error { + color: #b94a48; + background-color: #f2dede; + border-color: #eed3d7; +} + +.alert-info { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} + +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} + +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} + +.alert-block p + p { + margin-top: 5px; +} + +.nav { + margin-bottom: 20px; + margin-left: 0; + list-style: none; +} + +.nav > li > a { + display: block; +} + +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} + +.nav > .pull-right { + float: right; +} + +.nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 20px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} + +.nav li + .nav-header { + margin-top: 9px; +} + +.nav-list { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 0; +} + +.nav-list > li > a, +.nav-list .nav-header { + margin-right: -15px; + margin-left: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} + +.nav-list > li > a { + padding: 3px 15px; +} + +.nav-list > .active > a, +.nav-list > .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} + +.nav-list [class^="icon-"] { + margin-right: 2px; +} + +.nav-list .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.nav-tabs, +.nav-pills { + *zoom: 1; +} + +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + line-height: 0; + content: ""; +} + +.nav-tabs:after, +.nav-pills:after { + clear: both; +} + +.nav-tabs > li, +.nav-pills > li { + float: left; +} + +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} + +.nav-tabs { + border-bottom: 1px solid #ddd; +} + +.nav-tabs > li { + margin-bottom: -1px; +} + +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: 20px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover { + color: #555555; + cursor: default; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} + +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.nav-pills > .active > a, +.nav-pills > .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} + +.nav-stacked > li { + float: none; +} + +.nav-stacked > li > a { + margin-right: 0; +} + +.nav-tabs.nav-stacked { + border-bottom: 0; +} + +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; +} + +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.nav-tabs.nav-stacked > li > a:hover { + z-index: 2; + border-color: #ddd; +} + +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} + +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} + +.nav-tabs .dropdown-menu { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.nav-pills .dropdown-menu { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.nav .dropdown-toggle .caret { + margin-top: 6px; + border-top-color: #0088cc; + border-bottom-color: #0088cc; +} + +.nav .dropdown-toggle:hover .caret { + border-top-color: #005580; + border-bottom-color: #005580; +} + +/* move down carets for tabs */ + +.nav-tabs .dropdown-toggle .caret { + margin-top: 8px; +} + +.nav .active .dropdown-toggle .caret { + border-top-color: #fff; + border-bottom-color: #fff; +} + +.nav-tabs .active .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.nav > .dropdown.active > a:hover { + cursor: pointer; +} + +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} + +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} + +.tabs-stacked .open > a:hover { + border-color: #999999; +} + +.tabbable { + *zoom: 1; +} + +.tabbable:before, +.tabbable:after { + display: table; + line-height: 0; + content: ""; +} + +.tabbable:after { + clear: both; +} + +.tab-content { + overflow: auto; +} + +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} + +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} + +.tab-content > .active, +.pill-content > .active { + display: block; +} + +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} + +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} + +.tabs-below > .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.tabs-below > .nav-tabs > li > a:hover { + border-top-color: #ddd; + border-bottom-color: transparent; +} + +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} + +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} + +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} + +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.tabs-left > .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} + +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} + +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} + +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.tabs-right > .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} + +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} + +.nav > .disabled > a { + color: #999999; +} + +.nav > .disabled > a:hover { + text-decoration: none; + cursor: default; + background-color: transparent; +} + +.navbar { + *position: relative; + *z-index: 2; + margin-bottom: 20px; + overflow: visible; + color: #777777; +} + +.navbar-inner { + min-height: 40px; + padding-right: 20px; + padding-left: 20px; + background-color: #fafafa; + background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2)); + background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); + background-image: linear-gradient(to bottom, #ffffff, #f2f2f2); + background-repeat: repeat-x; + border: 1px solid #d4d4d4; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); + *zoom: 1; + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); +} + +.navbar-inner:before, +.navbar-inner:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-inner:after { + clear: both; +} + +.navbar .container { + width: auto; +} + +.nav-collapse.collapse { + height: auto; +} + +.navbar .brand { + display: block; + float: left; + padding: 10px 20px 10px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + color: #777777; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .brand:hover { + text-decoration: none; +} + +.navbar-text { + margin-bottom: 0; + line-height: 40px; +} + +.navbar-link { + color: #777777; +} + +.navbar-link:hover { + color: #333333; +} + +.navbar .divider-vertical { + height: 40px; + margin: 0 9px; + border-right: 1px solid #ffffff; + border-left: 1px solid #f2f2f2; +} + +.navbar .btn, +.navbar .btn-group { + margin-top: 5px; +} + +.navbar .btn-group .btn, +.navbar .input-prepend .btn, +.navbar .input-append .btn { + margin-top: 0; +} + +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} + +.navbar-form:before, +.navbar-form:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-form:after { + clear: both; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .radio, +.navbar-form .checkbox { + margin-top: 5px; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .btn { + display: inline-block; + margin-bottom: 0; +} + +.navbar-form input[type="image"], +.navbar-form input[type="checkbox"], +.navbar-form input[type="radio"] { + margin-top: 3px; +} + +.navbar-form .input-append, +.navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} + +.navbar-form .input-append input, +.navbar-form .input-prepend input { + margin-top: 0; +} + +.navbar-search { + position: relative; + float: left; + margin-top: 5px; + margin-bottom: 0; +} + +.navbar-search .search-query { + padding: 4px 14px; + margin-bottom: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.navbar-static-top { + position: static; + width: 100%; + margin-bottom: 0; +} + +.navbar-static-top .navbar-inner { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; + margin-bottom: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + border-width: 0 0 1px; +} + +.navbar-fixed-bottom .navbar-inner { + border-width: 1px 0 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-right: 0; + padding-left: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.navbar-fixed-top { + top: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar-fixed-bottom { + bottom: 0; +} + +.navbar-fixed-bottom .navbar-inner { + -webkit-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} + +.navbar .nav.pull-right { + float: right; + margin-right: 0; +} + +.navbar .nav > li { + float: left; +} + +.navbar .nav > li > a { + float: none; + padding: 10px 15px 10px; + color: #777777; + text-decoration: none; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .nav .dropdown-toggle .caret { + margin-top: 8px; +} + +.navbar .nav > li > a:focus, +.navbar .nav > li > a:hover { + color: #333333; + text-decoration: none; + background-color: transparent; +} + +.navbar .nav > .active > a, +.navbar .nav > .active > a:hover, +.navbar .nav > .active > a:focus { + color: #555555; + text-decoration: none; + background-color: #e5e5e5; + -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); +} + +.navbar .btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-right: 5px; + margin-left: 5px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #ededed; + *background-color: #e5e5e5; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5)); + background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5); + background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5); + background-repeat: repeat-x; + border-color: #e5e5e5 #e5e5e5 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} + +.navbar .btn-navbar:hover, +.navbar .btn-navbar:active, +.navbar .btn-navbar.active, +.navbar .btn-navbar.disabled, +.navbar .btn-navbar[disabled] { + color: #ffffff; + background-color: #e5e5e5; + *background-color: #d9d9d9; +} + +.navbar .btn-navbar:active, +.navbar .btn-navbar.active { + background-color: #cccccc \9; +} + +.navbar .btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} + +.navbar .nav > li > .dropdown-menu:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.navbar .nav > li > .dropdown-menu:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + border-left: 6px solid transparent; + content: ''; +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:before { + top: auto; + bottom: -7px; + border-top: 7px solid #ccc; + border-bottom: 0; + border-top-color: rgba(0, 0, 0, 0.2); +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:after { + top: auto; + bottom: -6px; + border-top: 6px solid #ffffff; + border-bottom: 0; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + color: #555555; + background-color: #e5e5e5; +} + +.navbar .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #777777; + border-bottom-color: #777777; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.navbar .pull-right > li > .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:before, +.navbar .nav > li > .dropdown-menu.pull-right:before { + right: 12px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:after, +.navbar .nav > li > .dropdown-menu.pull-right:after { + right: 13px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu { + right: 100%; + left: auto; + margin-right: -1px; + margin-left: 0; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + +.navbar-inverse { + color: #999999; +} + +.navbar-inverse .navbar-inner { + background-color: #1b1b1b; + background-image: -moz-linear-gradient(top, #222222, #111111); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111)); + background-image: -webkit-linear-gradient(top, #222222, #111111); + background-image: -o-linear-gradient(top, #222222, #111111); + background-image: linear-gradient(to bottom, #222222, #111111); + background-repeat: repeat-x; + border-color: #252525; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0); +} + +.navbar-inverse .brand, +.navbar-inverse .nav > li > a { + color: #999999; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.navbar-inverse .brand:hover, +.navbar-inverse .nav > li > a:hover { + color: #ffffff; +} + +.navbar-inverse .nav > li > a:focus, +.navbar-inverse .nav > li > a:hover { + color: #ffffff; + background-color: transparent; +} + +.navbar-inverse .nav .active > a, +.navbar-inverse .nav .active > a:hover, +.navbar-inverse .nav .active > a:focus { + color: #ffffff; + background-color: #111111; +} + +.navbar-inverse .navbar-link { + color: #999999; +} + +.navbar-inverse .navbar-link:hover { + color: #ffffff; +} + +.navbar-inverse .divider-vertical { + border-right-color: #222222; + border-left-color: #111111; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { + color: #ffffff; + background-color: #111111; +} + +.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #999999; + border-bottom-color: #999999; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .navbar-search .search-query { + color: #ffffff; + background-color: #515151; + border-color: #111111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; +} + +.navbar-inverse .navbar-search .search-query:-moz-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:focus, +.navbar-inverse .navbar-search .search-query.focused { + padding: 5px 15px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + outline: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); +} + +.navbar-inverse .btn-navbar { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e0e0e; + *background-color: #040404; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404)); + background-image: -webkit-linear-gradient(top, #151515, #040404); + background-image: -o-linear-gradient(top, #151515, #040404); + background-image: linear-gradient(to bottom, #151515, #040404); + background-image: -moz-linear-gradient(top, #151515, #040404); + background-repeat: repeat-x; + border-color: #040404 #040404 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.navbar-inverse .btn-navbar:hover, +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active, +.navbar-inverse .btn-navbar.disabled, +.navbar-inverse .btn-navbar[disabled] { + color: #ffffff; + background-color: #040404; + *background-color: #000000; +} + +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active { + background-color: #000000 \9; +} + +.breadcrumb { + padding: 8px 15px; + margin: 0 0 20px; + list-style: none; + background-color: #f5f5f5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.breadcrumb li { + display: inline-block; + *display: inline; + text-shadow: 0 1px 0 #ffffff; + *zoom: 1; +} + +.breadcrumb .divider { + padding: 0 5px; + color: #ccc; +} + +.breadcrumb .active { + color: #999999; +} + +.pagination { + height: 40px; + margin: 20px 0; +} + +.pagination ul { + display: inline-block; + *display: inline; + margin-bottom: 0; + margin-left: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + *zoom: 1; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.pagination ul > li { + display: inline; +} + +.pagination ul > li > a, +.pagination ul > li > span { + float: left; + padding: 0 14px; + line-height: 38px; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; + border-left-width: 0; +} + +.pagination ul > li > a:hover, +.pagination ul > .active > a, +.pagination ul > .active > span { + background-color: #f5f5f5; +} + +.pagination ul > .active > a, +.pagination ul > .active > span { + color: #999999; + cursor: default; +} + +.pagination ul > .disabled > span, +.pagination ul > .disabled > a, +.pagination ul > .disabled > a:hover { + color: #999999; + cursor: default; + background-color: transparent; +} + +.pagination ul > li:first-child > a, +.pagination ul > li:first-child > span { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.pagination ul > li:last-child > a, +.pagination ul > li:last-child > span { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.pagination-centered { + text-align: center; +} + +.pagination-right { + text-align: right; +} + +.pager { + margin: 20px 0; + text-align: center; + list-style: none; + *zoom: 1; +} + +.pager:before, +.pager:after { + display: table; + line-height: 0; + content: ""; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager a, +.pager span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} + +.pager .next a, +.pager .next span { + float: right; +} + +.pager .previous a { + float: left; +} + +.pager .disabled a, +.pager .disabled a:hover, +.pager .disabled span { + color: #999999; + cursor: default; + background-color: #fff; +} + +.modal-open .modal .dropdown-menu { + z-index: 2050; +} + +.modal-open .modal .dropdown.open { + *z-index: 2050; +} + +.modal-open .modal .popover { + z-index: 2060; +} + +.modal-open .modal .tooltip { + z-index: 2080; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop, +.modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + width: 560px; + margin: -250px 0 0 -280px; + overflow: auto; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} + +.modal.fade { + top: -25%; + -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out; +} + +.modal.fade.in { + top: 50%; +} + +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} + +.modal-header .close { + margin-top: 2px; +} + +.modal-header h3 { + margin: 0; + line-height: 30px; +} + +.modal-body { + max-height: 400px; + padding: 15px; + overflow-y: auto; +} + +.modal-form { + margin-bottom: 0; +} + +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + line-height: 0; + content: ""; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} + +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} + +.tooltip { + position: absolute; + z-index: 1030; + display: block; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.tooltip.top { + margin-top: -3px; +} + +.tooltip.right { + margin-left: 3px; +} + +.tooltip.bottom { + margin-top: 3px; +} + +.tooltip.left { + margin-left: -3px; +} + +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-right-color: #000000; + border-width: 5px 5px 5px 0; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-left-color: #000000; + border-width: 5px 0 5px 5px; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + width: 236px; + padding: 1px; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.popover.top { + margin-bottom: 10px; +} + +.popover.right { + margin-left: 10px; +} + +.popover.bottom { + margin-top: 10px; +} + +.popover.left { + margin-right: 10px; +} + +.popover-title { + padding: 8px 14px; + margin: 0; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + -webkit-border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; +} + +.popover-content { + padding: 9px 14px; +} + +.popover-content p, +.popover-content ul, +.popover-content ol { + margin-bottom: 0; +} + +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: inline-block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.popover .arrow:after { + z-index: -1; + content: ""; +} + +.popover.top .arrow { + bottom: -10px; + left: 50%; + margin-left: -10px; + border-top-color: #ffffff; + border-width: 10px 10px 0; +} + +.popover.top .arrow:after { + bottom: -1px; + left: -11px; + border-top-color: rgba(0, 0, 0, 0.25); + border-width: 11px 11px 0; +} + +.popover.right .arrow { + top: 50%; + left: -10px; + margin-top: -10px; + border-right-color: #ffffff; + border-width: 10px 10px 10px 0; +} + +.popover.right .arrow:after { + bottom: -11px; + left: -1px; + border-right-color: rgba(0, 0, 0, 0.25); + border-width: 11px 11px 11px 0; +} + +.popover.bottom .arrow { + top: -10px; + left: 50%; + margin-left: -10px; + border-bottom-color: #ffffff; + border-width: 0 10px 10px; +} + +.popover.bottom .arrow:after { + top: -1px; + left: -11px; + border-bottom-color: rgba(0, 0, 0, 0.25); + border-width: 0 11px 11px; +} + +.popover.left .arrow { + top: 50%; + right: -10px; + margin-top: -10px; + border-left-color: #ffffff; + border-width: 10px 0 10px 10px; +} + +.popover.left .arrow:after { + right: -1px; + bottom: -11px; + border-left-color: rgba(0, 0, 0, 0.25); + border-width: 11px 0 11px 11px; +} + +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} + +.thumbnails:before, +.thumbnails:after { + display: table; + line-height: 0; + content: ""; +} + +.thumbnails:after { + clear: both; +} + +.row-fluid .thumbnails { + margin-left: 0; +} + +.thumbnails > li { + float: left; + margin-bottom: 20px; + margin-left: 20px; +} + +.thumbnail { + display: block; + padding: 4px; + line-height: 20px; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} + +.thumbnail > img { + display: block; + max-width: 100%; + margin-right: auto; + margin-left: auto; +} + +.thumbnail .caption { + padding: 9px; + color: #555555; +} + +.label, +.badge { + font-size: 11.844px; + font-weight: bold; + line-height: 14px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + white-space: nowrap; + vertical-align: baseline; + background-color: #999999; +} + +.label { + padding: 1px 4px 2px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.badge { + padding: 1px 9px 2px; + -webkit-border-radius: 9px; + -moz-border-radius: 9px; + border-radius: 9px; +} + +a.label:hover, +a.badge:hover { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.label-important, +.badge-important { + background-color: #b94a48; +} + +.label-important[href], +.badge-important[href] { + background-color: #953b39; +} + +.label-warning, +.badge-warning { + background-color: #f89406; +} + +.label-warning[href], +.badge-warning[href] { + background-color: #c67605; +} + +.label-success, +.badge-success { + background-color: #468847; +} + +.label-success[href], +.badge-success[href] { + background-color: #356635; +} + +.label-info, +.badge-info { + background-color: #3a87ad; +} + +.label-info[href], +.badge-info[href] { + background-color: #2d6987; +} + +.label-inverse, +.badge-inverse { + background-color: #333333; +} + +.label-inverse[href], +.badge-inverse[href] { + background-color: #1a1a1a; +} + +.btn .label, +.btn .badge { + position: relative; + top: -1px; +} + +.btn-mini .label, +.btn-mini .badge { + top: 0; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-moz-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-ms-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-o-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +.progress { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress .bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + color: #ffffff; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(to bottom, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress .bar + .bar { + -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); +} + +.progress-striped .bar { + background-color: #149bdf; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} + +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-danger .bar, +.progress .bar-danger { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(to bottom, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); +} + +.progress-danger.progress-striped .bar, +.progress-striped .bar-danger { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-success .bar, +.progress .bar-success { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(to bottom, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); +} + +.progress-success.progress-striped .bar, +.progress-striped .bar-success { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-info .bar, +.progress .bar-info { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(to bottom, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); +} + +.progress-info.progress-striped .bar, +.progress-striped .bar-info { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-warning .bar, +.progress .bar-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); +} + +.progress-warning.progress-striped .bar, +.progress-striped .bar-warning { + background-color: #fbb450; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.accordion { + margin-bottom: 20px; +} + +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.accordion-heading { + border-bottom: 0; +} + +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +.accordion-toggle { + cursor: pointer; +} + +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} + +.carousel { + position: relative; + margin-bottom: 20px; + line-height: 1; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel .item > img { + display: block; + line-height: 1; +} + +.carousel .active, +.carousel .next, +.carousel .prev { + display: block; +} + +.carousel .active { + left: 0; +} + +.carousel .next, +.carousel .prev { + position: absolute; + top: 0; + width: 100%; +} + +.carousel .next { + left: 100%; +} + +.carousel .prev { + left: -100%; +} + +.carousel .next.left, +.carousel .prev.right { + left: 0; +} + +.carousel .active.left { + left: -100%; +} + +.carousel .active.right { + left: 100%; +} + +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.right { + right: 15px; + left: auto; +} + +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.carousel-caption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + padding: 15px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} + +.carousel-caption h4, +.carousel-caption p { + line-height: 20px; + color: #ffffff; +} + +.carousel-caption h4 { + margin: 0 0 5px; +} + +.carousel-caption p { + margin-bottom: 0; +} + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #eeeeee; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; + color: inherit; +} + +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 30px; + color: inherit; +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +.hide { + display: none; +} + +.show { + display: block; +} + +.invisible { + visibility: hidden; +} + +.affix { + position: fixed; +} diff --git a/docs/public/bootstrap/css/bootstrap.min.css b/docs/public/bootstrap/css/bootstrap.min.css new file mode 100644 index 00000000..31d8b960 --- /dev/null +++ b/docs/public/bootstrap/css/bootstrap.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v2.1.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}.text-warning{color:#c09853}.text-error{color:#b94a48}.text-info{color:#3a87ad}.text-success{color:#468847}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:1;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1{font-size:36px;line-height:40px}h2{font-size:30px;line-height:40px}h3{font-size:24px;line-height:40px}h4{font-size:18px;line-height:20px}h5{font-size:14px;line-height:20px}h6{font-size:12px;line-height:20px}h1 small{font-size:24px}h2 small{font-size:18px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:9px;font-size:14px;line-height:20px;color:#555;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal;cursor:pointer}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:18px;padding-left:18px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"]{float:left}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info>label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;font-size:14px;vertical-align:top;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append .add-on,.input-append .btn{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child,.table-bordered tfoot:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child,.table-bordered tfoot:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topleft:4px}.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9}.table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5}table [class*=span],.row-fluid table [class*=span]{display:table-cell;float:none;margin-left:0}.table .span1{float:none;width:44px;margin-left:0}.table .span2{float:none;width:124px;margin-left:0}.table .span3{float:none;width:204px;margin-left:0}.table .span4{float:none;width:284px;margin-left:0}.table .span5{float:none;width:364px;margin-left:0}.table .span6{float:none;width:444px;margin-left:0}.table .span7{float:none;width:524px;margin-left:0}.table .span8{float:none;width:604px;margin-left:0}.table .span9{float:none;width:684px;margin-left:0}.table .span10{float:none;width:764px;margin-left:0}.table .span11{float:none;width:844px;margin-left:0}.table .span12{float:none;width:924px;margin-left:0}.table .span13{float:none;width:1004px;margin-left:0}.table .span14{float:none;width:1084px;margin-left:0}.table .span15{float:none;width:1164px;margin-left:0}.table .span16{float:none;width:1244px;margin-left:0}.table .span17{float:none;width:1324px;margin-left:0}.table .span18{float:none;width:1404px;margin-left:0}.table .span19{float:none;width:1484px;margin-left:0}.table .span20{float:none;width:1564px;margin-left:0}.table .span21{float:none;width:1644px;margin-left:0}.table .span22{float:none;width:1724px;margin-left:0}.table .span23{float:none;width:1804px;margin-left:0}.table .span24{float:none;width:1884px;margin-left:0}.table tbody tr.success td{background-color:#dff0d8}.table tbody tr.error td{background-color:#f2dede}.table tbody tr.warning td{background-color:#fcf8e3}.table tbody tr.info td{background-color:#d9edf7}.table-hover tbody tr.success:hover td{background-color:#d0e9c6}.table-hover tbody tr.error:hover td{background-color:#ebcccc}.table-hover tbody tr.warning:hover td{background-color:#faf2cc}.table-hover tbody tr.info:hover td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-tabs>.active>a>[class^="icon-"],.nav-tabs>.active>a>[class*=" icon-"],.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{color:#fff;text-decoration:none;background-color:#08c;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#fff;text-decoration:none;background-color:#08c;background-color:#0081c2;background-image:linear-gradient(to bottom,#08c,#0077b3);background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999}.dropdown-menu .disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 14px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;*line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #bbb;*border:0;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover{color:#333;text-decoration:none;background-color:#e6e6e6;*background-color:#d9d9d9;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-color:#e6e6e6;background-color:#d9d9d9 \9;background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-color:#e6e6e6;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:9px 14px;font-size:16px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.btn-large [class^="icon-"]{margin-top:2px}.btn-small{padding:3px 9px;font-size:12px;line-height:18px}.btn-small [class^="icon-"]{margin-top:0}.btn-mini{padding:2px 6px;font-size:11px;line-height:17px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn{border-color:#c5c5c5;border-color:rgba(0,0,0,0.15) rgba(0,0,0,0.15) rgba(0,0,0,0.25)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-image:-moz-linear-gradient(top,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-image:-moz-linear-gradient(top,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-image:-moz-linear-gradient(top,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover{color:#333;text-decoration:none}.btn-group{position:relative;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1}.btn-toolbar .btn+.btn,.btn-toolbar .btn-group+.btn,.btn-toolbar .btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu{font-size:14px}.btn-group>.btn-mini{font-size:11px}.btn-group>.btn-small{font-size:12px}.btn-group>.btn-large{font-size:16px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-mini .caret,.btn-small .caret,.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.dropup .btn-large .caret{border-top:0;border-bottom:5px solid #000}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical .btn{display:block;float:none;width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical .btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical .btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical .btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical .btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical .btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;color:#c09853;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible;color:#777}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px}.navbar-link{color:#777}.navbar-link:hover{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;width:100%;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.1),0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.1),0 1px 10px rgba(0,0,0,0.1);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.1),0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:inset 0 1px 0 rgba(0,0,0,0.1),0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 0 rgba(0,0,0,0.1),0 -1px 10px rgba(0,0,0,0.1);box-shadow:inset 0 1px 0 rgba(0,0,0,0.1),0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse{color:#999}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#fff}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-image:-moz-linear-gradient(top,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb .divider{padding:0 5px;color:#ccc}.breadcrumb .active{color:#999}.pagination{height:40px;margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:0 14px;line-height:38px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager a,.pager span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager a:hover{text-decoration:none;background-color:#f5f5f5}.pager .next a,.pager .next span{float:right}.pager .previous a{float:left}.pager .disabled a,.pager .disabled a:hover,.pager .disabled span{color:#999;cursor:default;background-color:#fff}.modal-open .modal .dropdown-menu{z-index:2050}.modal-open .modal .dropdown.open{*z-index:2050}.modal-open .modal .popover{z-index:2060}.modal-open .modal .tooltip{z-index:2080}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:50%;left:50%;z-index:1050;width:560px;margin:-250px 0 0 -280px;overflow:auto;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:50%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.tooltip{position:absolute;z-index:1030;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-3px}.tooltip.right{margin-left:3px}.tooltip.bottom{margin-top:3px}.tooltip.left{margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-bottom:10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-right:10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0}.popover .arrow,.popover .arrow:after{position:absolute;display:inline-block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow:after{z-index:-1;content:""}.popover.top .arrow{bottom:-10px;left:50%;margin-left:-10px;border-top-color:#fff;border-width:10px 10px 0}.popover.top .arrow:after{bottom:-1px;left:-11px;border-top-color:rgba(0,0,0,0.25);border-width:11px 11px 0}.popover.right .arrow{top:50%;left:-10px;margin-top:-10px;border-right-color:#fff;border-width:10px 10px 10px 0}.popover.right .arrow:after{bottom:-11px;left:-1px;border-right-color:rgba(0,0,0,0.25);border-width:11px 11px 11px 0}.popover.bottom .arrow{top:-10px;left:50%;margin-left:-10px;border-bottom-color:#fff;border-width:0 10px 10px}.popover.bottom .arrow:after{top:-1px;left:-11px;border-bottom-color:rgba(0,0,0,0.25);border-width:0 11px 11px}.popover.left .arrow{top:50%;right:-10px;margin-top:-10px;border-left-color:#fff;border-width:10px 0 10px 10px}.popover.left .arrow:after{right:-1px;bottom:-11px;border-left-color:rgba(0,0,0,0.25);border-width:11px 0 11px 11px}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.label,.badge{font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{padding:1px 4px 2px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding:1px 9px 2px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}a.label:hover,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel .item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel .item>img{display:block;line-height:1}.carousel .active,.carousel .next,.carousel .prev{display:block}.carousel .active{left:0}.carousel .next,.carousel .prev{position:absolute;top:0;width:100%}.carousel .next{left:100%}.carousel .prev{left:-100%}.carousel .next.left,.carousel .prev.right{left:0}.carousel .active.left{left:-100%}.carousel .active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit p{font-size:18px;font-weight:200;line-height:30px;color:inherit}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed} diff --git a/docs/public/bootstrap/img/glyphicons-halflings-white.png b/docs/public/bootstrap/img/glyphicons-halflings-white.png new file mode 100644 index 0000000000000000000000000000000000000000..3bf6484a29d8da269f9bc874b25493a45fae3bae GIT binary patch literal 8777 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 B7G?kd literal 0 HcmV?d00001 diff --git a/docs/public/bootstrap/img/glyphicons-halflings.png b/docs/public/bootstrap/img/glyphicons-halflings.png new file mode 100644 index 0000000000000000000000000000000000000000..a9969993201f9cee63cf9f49217646347297b643 GIT binary patch literal 12799 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 literal 0 HcmV?d00001 diff --git a/docs/public/bootstrap/js/bootstrap.js b/docs/public/bootstrap/js/bootstrap.js new file mode 100644 index 00000000..f73fcb8e --- /dev/null +++ b/docs/public/bootstrap/js/bootstrap.js @@ -0,0 +1,2027 @@ +/* =================================================== + * bootstrap-transition.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#transitions + * =================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + $(function () { + + "use strict"; // jshint ;_; + + + /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) + * ======================================================= */ + + $.support.transition = (function () { + + var transitionEnd = (function () { + + var el = document.createElement('bootstrap') + , transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' + } + , name + + for (name in transEndEventNames){ + if (el.style[name] !== undefined) { + return transEndEventNames[name] + } + } + + }()) + + return transitionEnd && { + end: transitionEnd + } + + })() + + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-alert.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent.trigger(e = $.Event('close')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}(window.jQuery);/* ============================================================ + * bootstrap-button.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.closest('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}(window.jQuery);/* ========================================================== + * bootstrap-carousel.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = options + this.options.slide && this.slide(this.options.slide) + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.prototype = { + + cycle: function (e) { + if (!e) this.paused = false + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.item.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function (e) { + if (!e) this.paused = true + if (this.$element.find('.next, .prev').length && $.support.transition.end) { + this.$element.trigger($.support.transition.end) + this.cycle() + } + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.item.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + , e = $.Event('slide', { + relatedTarget: $next[0] + }) + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if ($next.hasClass('active')) return + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) + , action = typeof option == 'string' ? option : options.slide + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + , pause: 'hover' + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}(window.jQuery);/* ============================================================= + * bootstrap-collapse.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* COLLAPSE PUBLIC CLASS DEFINITION + * ================================ */ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options.parent) { + this.$parent = $(this.options.parent) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension + , scroll + , actives + , hasData + + if (this.transitioning) return + + dimension = this.dimension() + scroll = $.camelCase(['scroll', dimension].join('-')) + actives = this.$parent && this.$parent.find('> .accordion-group > .in') + + if (actives && actives.length) { + hasData = actives.data('collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', $.Event('show'), 'shown') + $.support.transition && this.$element[dimension](this.$element[0][scroll]) + } + + , hide: function () { + var dimension + if (this.transitioning) return + dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', $.Event('hide'), 'hidden') + this.$element[dimension](0) + } + + , reset: function (size) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') + + return this + } + + , transition: function (method, startEvent, completeEvent) { + var that = this + , complete = function () { + if (startEvent.type == 'show') that.reset() + that.transitioning = 0 + that.$element.trigger(completeEvent) + } + + this.$element.trigger(startEvent) + + if (startEvent.isDefaultPrevented()) return + + this.transitioning = 1 + + this.$element[method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + $(target).collapse(option) + }) + }) + +}(window.jQuery);/* ============================================================ + * bootstrap-dropdown.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle=dropdown]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , isActive + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + $parent.toggleClass('open') + $this.focus() + } + + return false + } + + , keydown: function (e) { + var $this + , $items + , $active + , $parent + , isActive + , index + + if (!/(38|40|27)/.test(e.keyCode)) return + + $this = $(this) + + e.preventDefault() + e.stopPropagation() + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + if (!isActive || (isActive && e.keyCode == 27)) return $this.click() + + $items = $('[role=menu] li:not(.divider) a', $parent) + + if (!$items.length) return + + index = $items.index($items.filter(':focus')) + + if (e.keyCode == 38 && index > 0) index-- // up + if (e.keyCode == 40 && index < $items.length - 1) index++ // down + if (!~index) index = 0 + + $items + .eq(index) + .focus() + } + + } + + function clearMenus() { + getParent($(toggle)) + .removeClass('open') + } + + function getParent($this) { + var selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + return $parent + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html') + .on('click.dropdown.data-api touchstart.dropdown.data-api', clearMenus) + $('body') + .on('click.dropdown touchstart.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) + .on('click.dropdown.data-api touchstart.dropdown.data-api' , toggle, Dropdown.prototype.toggle) + .on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown) + }) + +}(window.jQuery);/* ========================================================= + * bootstrap-modal.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function (element, options) { + this.options = options + this.$element = $(element) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + this.options.remote && this.$element.find('.modal-body').load(this.options.remote) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + , e = $.Event('show') + + this.$element.trigger(e) + + if (this.isShown || e.isDefaultPrevented()) return + + $('body').addClass('modal-open') + + this.isShown = true + + this.escape() + + this.backdrop(function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + if (!that.$element.parent().length) { + that.$element.appendTo(document.body) //don't move modals dom position + } + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element + .addClass('in') + .attr('aria-hidden', false) + .focus() + + that.enforceFocus() + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + } + + , hide: function (e) { + e && e.preventDefault() + + var that = this + + e = $.Event('hide') + + this.$element.trigger(e) + + if (!this.isShown || e.isDefaultPrevented()) return + + this.isShown = false + + $('body').removeClass('modal-open') + + this.escape() + + $(document).off('focusin.modal') + + this.$element + .removeClass('in') + .attr('aria-hidden', true) + + $.support.transition && this.$element.hasClass('fade') ? + this.hideWithTransition() : + this.hideModal() + } + + , enforceFocus: function () { + var that = this + $(document).on('focusin.modal', function (e) { + if (that.$element[0] !== e.target && !that.$element.has(e.target).length) { + that.$element.focus() + } + }) + } + + , escape: function () { + var that = this + if (this.isShown && this.options.keyboard) { + this.$element.on('keyup.dismiss.modal', function ( e ) { + e.which == 27 && that.hide() + }) + } else if (!this.isShown) { + this.$element.off('keyup.dismiss.modal') + } + } + + , hideWithTransition: function () { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + that.hideModal() + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + that.hideModal() + }) + } + + , hideModal: function (that) { + this.$element + .hide() + .trigger('hidden') + + this.backdrop() + } + + , removeBackdrop: function () { + this.$backdrop.remove() + this.$backdrop = null + } + + , backdrop: function (callback) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $(' -
- - - {{body | markdownify}} +
+
{{body1 | markdownify}}
+
{{body2 | markdownify}}
+
{{body3 | markdownify}}
+
+
+ {{tail | markdownify}}
{% include "shared/footer" %} diff --git a/docs/templates/manual.liquid b/docs/templates/manual.liquid index b3eb2e2f..af22fcad 100644 --- a/docs/templates/manual.liquid +++ b/docs/templates/manual.liquid @@ -2,7 +2,7 @@ {% include "shared/head" %} - {% include "shared/header" %} + {% include "shared/header" %}

{{headline}}

+ {{ body | markdownify }} {% for section in sections %}

{{section.title}}

From 5863160112ac8b50f8b7b7da60044a78f8f261de Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 18 Sep 2012 23:32:24 +0100 Subject: [PATCH 093/284] Implement the 'add' builtin promised by the docs' examples. --- builtin.c | 20 +++++++++++++++++ docs/content/3.manual/manual.yml | 37 ++++++++++++++++++++++++++++++++ testdata | 4 ++++ 3 files changed, 61 insertions(+) diff --git a/builtin.c b/builtin.c index f291a95e..1eee5bb5 100644 --- a/builtin.c +++ b/builtin.c @@ -90,6 +90,25 @@ static void f_divide(jv input[], jv output[]) { } } +static void f_add(jv input[], jv output[]) { + jv array = input[0]; + if (jv_get_kind(array) != JV_KIND_ARRAY) { + output[0] = jv_invalid_with_msg(jv_string_fmt("Cannot add elements of an %s", + jv_kind_name(jv_get_kind(array)))); + } else if (jv_array_length(jv_copy(array)) == 0) { + output[0] = jv_null(); + } else { + jv sum = jv_array_get(jv_copy(array), 0); + for (int i = 1; i < jv_array_length(jv_copy(array)); i++) { + jv x = jv_array_get(jv_copy(array), i); + jv add_args[] = {jv_null(), x, sum}; + f_plus(add_args, &sum); + } + output[0] = sum; + } + jv_free(array); +} + static void f_equal(jv input[], jv output[]) { jv_free(input[0]); output[0] = jv_bool(jv_equal(input[2], input[1])); @@ -185,6 +204,7 @@ static struct cfunction function_list[] = { {f_equal, "_equal", CALL_BUILTIN_3_1}, {f_length, "length", CALL_BUILTIN_1_1}, {f_type, "type", CALL_BUILTIN_1_1}, + {f_add, "add", CALL_BUILTIN_1_1}, }; static struct symbol_table cbuiltins = {function_list, sizeof(function_list)/sizeof(function_list[0])}; diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml index 417432b4..10998dce 100644 --- a/docs/content/3.manual/manual.yml +++ b/docs/content/3.manual/manual.yml @@ -321,6 +321,43 @@ sections: input: '[[1,2], "string", {"a":2}, null]' output: [2, 6, 1, 0] + - title: `map(x)` + body: | + + For any filter `x`, `map(x)` will run that filter for each + element of the input array, and produce the outputs a new + array. `map(.+1)` will increment each element of an array of numbers. + + `map(x)` is equivalent to `[.[] | x]`. In fact, this is how + it's defined. + + examples: + - program: 'map(.+1)' + input: '[1,2,3]' + output: ['[2,3,4]'] + + - title: `add` + body: | + + The filter `add` takes as input an array, and produces as + output the elements of the array added together. This might + mean summed, concatenated or merged depending on the types + of the elements of the input array - the rules are the same + as those for the `+` operator (described above). + + If the input is an empty array, `add` returns `null`. + + examples: + - program: add + input: '["a","b","c"]' + output: ["abc"] + - program: add + input: '[1, 2, 3]' + output: [6] + - program: add + input: '[]' + output: ["null"] + - title: `tonumber` body: | diff --git a/testdata b/testdata index 7357ccb2..8a289973 100644 --- a/testdata +++ b/testdata @@ -211,6 +211,10 @@ null null [1,2,3,4] +map(add) +[[], [1,2,3], ["a","b","c"], [[3],[4,5],[6]], [{"a":1}, {"b":2}, {"a":3}]] +[null, 6, "abc", [3,4,5,6], {"a":3, "b": 2}] + # # User-defined functions # Oh god. From 305059ff9f630b7fb140ef61fab5613483a75ff0 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 18 Sep 2012 23:37:46 +0100 Subject: [PATCH 094/284] Usage messages if jq is run with no arguments. Beats segfaulting. --- main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/main.c b/main.c index 776c9575..92a7c652 100644 --- a/main.c +++ b/main.c @@ -8,7 +8,20 @@ #include "parser.h" #include "execute.h" +static const char* progname; + +static void usage() { + fprintf(stderr, "\njq - commandline JSON processor\n"); + fprintf(stderr, "Usage: %s \n\n", progname); + fprintf(stderr, "For a description of how to write jq filters and\n"); + fprintf(stderr, "why you might want to, see the jq documentation at\n"); + fprintf(stderr, "http://stedolan.github.com/jq\n\n"); + exit(1); +} + int main(int argc, char* argv[]) { + if (argc) progname = argv[0]; + if (argc != 2 || !strcmp(argv[1], "--help") || !strcmp(argv[1], "--version")) usage(); struct bytecode* bc = jq_compile(argv[1]); if (!bc) return 1; From 3898f744dc624782ce21ef287b452183425154eb Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 18 Sep 2012 23:40:19 +0100 Subject: [PATCH 095/284] Add a README --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..8f7b240d --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +jq +== + +jq is a command-line JSON processor. + +If you want to learn to use jq, read the documentation at +[https://stedolan.github.com/jq](https://stedolan.github.com/jq). This +documentation is generated from the docs/ folder of this repository. + +If you want to hack on jq, feel free, but be warned that its internals +are not well-documented at the moment. Bring a hard hat and a shovel. + +You can find some basic build instructions at +[https://stedolan.github.com/jq/download](https://stedolan.github.com/jq/download) From 134b062be7cf2b62d0e69772836e6312fd9e60d5 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 18 Sep 2012 23:45:30 +0100 Subject: [PATCH 096/284] Fix a parsing bug for \uXXXX escapes (some invalid escapes were accepted). Found by gcc -O -Wall identifying a use of uninitialised variables. --- jv_parse.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/jv_parse.c b/jv_parse.c index e4565ef7..63cdf935 100644 --- a/jv_parse.c +++ b/jv_parse.c @@ -155,6 +155,7 @@ static int unhex4(char* hex) { if ('0' <= c && c <= '9') n = c - '0'; else if ('a' <= c && c <= 'f') n = c - 'a' + 10; else if ('A' <= c && c <= 'F') n = c - 'A' + 10; + else return -1; r <<= 4; r |= n; } @@ -186,7 +187,10 @@ static pfunc found_string(struct jv_parser* p) { /* ahh, the complicated case */ if (in + 4 > end) return "Invalid \\uXXXX escape"; - unsigned long codepoint = unhex4(in); + int hexvalue = unhex4(in); + if (hexvalue < 0) + return "Invalid characters in \\uXXXX escape"; + unsigned long codepoint = (unsigned long)hexvalue; in += 4; if (0xD800 <= codepoint && codepoint <= 0xDBFF) { /* who thought UTF-16 surrogate pairs were a good idea? */ From 71ab537ee924e0490cde43da6e678963618deea0 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 18 Sep 2012 23:46:23 +0100 Subject: [PATCH 097/284] Initialise some variables to keep gcc happy. --- compile.c | 2 +- jv_dtoa.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compile.c b/compile.c index 719a2706..fe50c70a 100644 --- a/compile.c +++ b/compile.c @@ -527,7 +527,7 @@ static int compile(struct locfile* locations, struct bytecode* bc, block b) { int nargs = curr->imm.intval; assert(nargs > 0); code[pos++] = (uint16_t)nargs; - int desired_params; + int desired_params = 0; for (int i=0; inext; assert(curr && opcode_describe(curr->op)->flags & OP_IS_CALL_PSEUDO); diff --git a/jv_dtoa.c b/jv_dtoa.c index 2c27c880..b200c462 100644 --- a/jv_dtoa.c +++ b/jv_dtoa.c @@ -2120,7 +2120,7 @@ bigcomp (struct dtoa_context* C, U *rv, const char *s0, BCinfo *bc) { Bigint *b, *d; - int b2, bbits, d2, dd, dig, dsign, i, j, nd, nd0, p2, p5, speccase; + int b2, bbits, d2, dd=0, dig, dsign, i, j, nd, nd0, p2, p5, speccase; dsign = bc->dsign; nd = bc->nd; From c463877e17fee6b5a82a235c98adbccbebbda96e Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Wed, 19 Sep 2012 00:08:02 +0100 Subject: [PATCH 098/284] Add binaries and update download docs. --- docs/content/1.tutorial/default.yml | 2 +- docs/content/2.download/default.yml | 11 ++++++++--- docs/content/2.download/linux_x86_64/jq | Bin 0 -> 447776 bytes docs/content/2.download/osx_64/jq | Bin 0 -> 185432 bytes docs/templates/index.liquid | 4 ++-- 5 files changed, 11 insertions(+), 6 deletions(-) create mode 100755 docs/content/2.download/linux_x86_64/jq create mode 100755 docs/content/2.download/osx_64/jq diff --git a/docs/content/1.tutorial/default.yml b/docs/content/1.tutorial/default.yml index 61ff97ed..f41e5aae 100644 --- a/docs/content/1.tutorial/default.yml +++ b/docs/content/1.tutorial/default.yml @@ -1,7 +1,7 @@ headline: Tutorial body: - text: | - + Twitter have a JSON API, so let's play with that. This URL gets us the last 5 tweets about JSON: diff --git a/docs/content/2.download/default.yml b/docs/content/2.download/default.yml index 03c9cb7f..9d69780a 100644 --- a/docs/content/2.download/default.yml +++ b/docs/content/2.download/default.yml @@ -7,13 +7,18 @@ body: possible to build it for nearly any platform. Prebuilt binaries are available for Linux (64-bit x86) and OS X. - * [Download binary for 64-bit Linux](/download/linux/x68_64/jq) - * [Download binary for OS X](/download/osx/64/jq) + * [Download binary for 64-bit Linux](/download/linux_x86_64/jq) + * [Download binary for OS X](/download/osx_64/jq) * [Download source](/download/source/jq.tgz) + The binaries should just run, but you may need to make them + executable first using: + + chmod +x jq + jq is licensed under the MIT license. For all of the gory details, read the file `COPYING` in the source distribution. - + Hacking on jq ============= diff --git a/docs/content/2.download/linux_x86_64/jq b/docs/content/2.download/linux_x86_64/jq new file mode 100755 index 0000000000000000000000000000000000000000..5a36b20225b33a60951fd05781a166fce908e17a GIT binary patch literal 447776 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 z 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 literal 0 HcmV?d00001 diff --git a/docs/templates/index.liquid b/docs/templates/index.liquid index 39ee0c5a..d2d06de5 100644 --- a/docs/templates/index.liquid +++ b/docs/templates/index.liquid @@ -16,8 +16,8 @@
From 483f6f2134cbfed6aea39931be38fc55b0826879 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Wed, 19 Sep 2012 00:34:49 +0100 Subject: [PATCH 099/284] Add some release stuff to Makefile. --- .gitignore | 3 +++ Makefile | 13 ++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 50e45cc8..e43b388c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ jv_test jv_parse parsertest*~ + +# Something delightfully recursive happens otherwise +docs/content/2.download/source/* \ No newline at end of file diff --git a/Makefile b/Makefile index 7348b292..807a4b21 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC=gcc -Wextra -Wall -Wno-missing-field-initializers -Wno-unused-parameter -std=gnu99 -ggdb -Wno-unused-function -.PHONY: all clean -all: parsertest +.PHONY: all clean releasedep tarball +all: jq clean: make -Bnd | grep 'Must remake target' | \ @@ -28,9 +28,16 @@ jq_test: $(JQ_SRC) jq_test.c $(CC) -DJQ_DEBUG=1 -o $@ $^ jq: $(JQ_SRC) main.c - $(CC) -DJQ_DEBUG=0 -o $@ $^ + $(CC) -O -DJQ_DEBUG=0 -o $@ $^ test: jq_test valgrind --error-exitcode=1 -q --leak-check=full ./jq_test >/dev/null + +releasedep: lexer.gen.c parser.gen.c jv_utf8_tables.gen.h + +docs/content/2.download/source/jq.tgz: jq + tar -czvf $@ `git ls-files; ls *.gen.*` + +tarball: docs/content/2.download/source/jq.tgz \ No newline at end of file From 26c7132237b990a29a9e77139037199d43923264 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Wed, 19 Sep 2012 00:36:37 +0100 Subject: [PATCH 100/284] Ensure 'make tarball' creates the required directories. --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 807a4b21..aac341f8 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,7 @@ test: jq_test releasedep: lexer.gen.c parser.gen.c jv_utf8_tables.gen.h docs/content/2.download/source/jq.tgz: jq + mkdir -p `dirname $@` tar -czvf $@ `git ls-files; ls *.gen.*` tarball: docs/content/2.download/source/jq.tgz \ No newline at end of file From 040604b7dbe2fcfb8cc69bc31dcb8bd80afcb4dc Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Wed, 19 Sep 2012 01:00:25 +0100 Subject: [PATCH 101/284] Use a theme from Bootswatch for docs. --- docs/public/bootstrap/css/bootstrap.css | 3004 +++++++++-------------- docs/public/css/base.scss | 4 + docs/site.yml | 6 +- 3 files changed, 1235 insertions(+), 1779 deletions(-) diff --git a/docs/public/bootstrap/css/bootstrap.css b/docs/public/bootstrap/css/bootstrap.css index 9fa6f766..d6a835ce 100644 --- a/docs/public/bootstrap/css/bootstrap.css +++ b/docs/public/bootstrap/css/bootstrap.css @@ -1,3 +1,4 @@ +@import url('http://fonts.googleapis.com/css?family=Muli'); /*! * Bootstrap v2.1.1 * @@ -7,7 +8,6 @@ * * Designed and built with all the love in the world @twitter by @mdo and @fat. */ - article, aside, details, @@ -20,7 +20,6 @@ nav, section { display: block; } - audio, canvas, video { @@ -28,28 +27,23 @@ video { *display: inline; *zoom: 1; } - audio:not([controls]) { display: none; } - html { font-size: 100%; -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; } - a:focus { outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } - a:hover, a:active { outline: 0; } - sub, sup { position: relative; @@ -57,28 +51,31 @@ sup { line-height: 0; vertical-align: baseline; } - sup { top: -0.5em; } - sub { bottom: -0.25em; } - img { - width: auto\9; - height: auto; + /* Responsive images (ensure images don't scale beyond their parents) */ + max-width: 100%; + /* Part 1: Set a maxium relative to the parent */ + + width: auto\9; + /* IE7-8 need help adjusting responsive images */ + + height: auto; + /* Part 2: Scale the height according to the width, otherwise you get stretching */ + vertical-align: middle; border: 0; -ms-interpolation-mode: bicubic; } - #map_canvas img { max-width: none; } - button, input, select, @@ -87,19 +84,16 @@ textarea { font-size: 100%; vertical-align: middle; } - button, input { *overflow: visible; line-height: normal; } - button::-moz-focus-inner, input::-moz-focus-inner { padding: 0; border: 0; } - button, input[type="button"], input[type="reset"], @@ -107,39 +101,32 @@ input[type="submit"] { cursor: pointer; -webkit-appearance: button; } - input[type="search"] { -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; -webkit-appearance: textfield; } - input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; } - textarea { overflow: auto; vertical-align: top; } - .clearfix { *zoom: 1; } - .clearfix:before, .clearfix:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .clearfix:after { clear: both; } - .hide-text { font: 0/0 a; color: transparent; @@ -147,499 +134,401 @@ textarea { background-color: transparent; border: 0; } - .input-block-level { display: block; width: 100%; min-height: 30px; -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } - body { margin: 0; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-family: "Muli", "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px; - line-height: 20px; - color: #333333; + line-height: 21px; + color: #2d2d2d; background-color: #ffffff; } - a { - color: #0088cc; + color: #558bc4; text-decoration: none; } - a:hover { - color: #005580; + color: #558bc4; text-decoration: underline; } - .img-rounded { -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; } - .img-polaroid { padding: 4px; background-color: #fff; border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.2); -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); - -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } - .img-circle { -webkit-border-radius: 500px; - -moz-border-radius: 500px; - border-radius: 500px; + -moz-border-radius: 500px; + border-radius: 500px; } - .row { margin-left: -20px; *zoom: 1; } - .row:before, .row:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .row:after { clear: both; } - [class*="span"] { float: left; min-height: 1px; margin-left: 20px; } - .container, .navbar-static-top .container, .navbar-fixed-top .container, .navbar-fixed-bottom .container { width: 940px; } - .span12 { width: 940px; } - .span11 { width: 860px; } - .span10 { width: 780px; } - .span9 { width: 700px; } - .span8 { width: 620px; } - .span7 { width: 540px; } - .span6 { width: 460px; } - .span5 { width: 380px; } - .span4 { width: 300px; } - .span3 { width: 220px; } - .span2 { width: 140px; } - .span1 { width: 60px; } - .offset12 { margin-left: 980px; } - .offset11 { margin-left: 900px; } - .offset10 { margin-left: 820px; } - .offset9 { margin-left: 740px; } - .offset8 { margin-left: 660px; } - .offset7 { margin-left: 580px; } - .offset6 { margin-left: 500px; } - .offset5 { margin-left: 420px; } - .offset4 { margin-left: 340px; } - .offset3 { margin-left: 260px; } - .offset2 { margin-left: 180px; } - .offset1 { margin-left: 100px; } - .row-fluid { width: 100%; *zoom: 1; } - .row-fluid:before, .row-fluid:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .row-fluid:after { clear: both; } - .row-fluid [class*="span"] { display: block; - float: left; width: 100%; min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + float: left; margin-left: 2.127659574468085%; *margin-left: 2.074468085106383%; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; } - .row-fluid [class*="span"]:first-child { margin-left: 0; } - .row-fluid .span12 { width: 100%; *width: 99.94680851063829%; } - .row-fluid .span11 { width: 91.48936170212765%; *width: 91.43617021276594%; } - .row-fluid .span10 { width: 82.97872340425532%; *width: 82.92553191489361%; } - .row-fluid .span9 { width: 74.46808510638297%; *width: 74.41489361702126%; } - .row-fluid .span8 { width: 65.95744680851064%; *width: 65.90425531914893%; } - .row-fluid .span7 { width: 57.44680851063829%; *width: 57.39361702127659%; } - .row-fluid .span6 { width: 48.93617021276595%; *width: 48.88297872340425%; } - .row-fluid .span5 { width: 40.42553191489362%; *width: 40.37234042553192%; } - .row-fluid .span4 { width: 31.914893617021278%; *width: 31.861702127659576%; } - .row-fluid .span3 { width: 23.404255319148934%; *width: 23.351063829787233%; } - .row-fluid .span2 { width: 14.893617021276595%; *width: 14.840425531914894%; } - .row-fluid .span1 { width: 6.382978723404255%; *width: 6.329787234042553%; } - .row-fluid .offset12 { margin-left: 104.25531914893617%; *margin-left: 104.14893617021275%; } - .row-fluid .offset12:first-child { margin-left: 102.12765957446808%; *margin-left: 102.02127659574467%; } - .row-fluid .offset11 { margin-left: 95.74468085106382%; *margin-left: 95.6382978723404%; } - .row-fluid .offset11:first-child { margin-left: 93.61702127659574%; *margin-left: 93.51063829787232%; } - .row-fluid .offset10 { margin-left: 87.23404255319149%; *margin-left: 87.12765957446807%; } - .row-fluid .offset10:first-child { margin-left: 85.1063829787234%; *margin-left: 84.99999999999999%; } - .row-fluid .offset9 { margin-left: 78.72340425531914%; *margin-left: 78.61702127659572%; } - .row-fluid .offset9:first-child { margin-left: 76.59574468085106%; *margin-left: 76.48936170212764%; } - .row-fluid .offset8 { margin-left: 70.2127659574468%; *margin-left: 70.10638297872339%; } - .row-fluid .offset8:first-child { margin-left: 68.08510638297872%; *margin-left: 67.9787234042553%; } - .row-fluid .offset7 { margin-left: 61.70212765957446%; *margin-left: 61.59574468085106%; } - .row-fluid .offset7:first-child { margin-left: 59.574468085106375%; *margin-left: 59.46808510638297%; } - .row-fluid .offset6 { margin-left: 53.191489361702125%; *margin-left: 53.085106382978715%; } - .row-fluid .offset6:first-child { margin-left: 51.063829787234035%; *margin-left: 50.95744680851063%; } - .row-fluid .offset5 { margin-left: 44.68085106382979%; *margin-left: 44.57446808510638%; } - .row-fluid .offset5:first-child { margin-left: 42.5531914893617%; *margin-left: 42.4468085106383%; } - .row-fluid .offset4 { margin-left: 36.170212765957444%; *margin-left: 36.06382978723405%; } - .row-fluid .offset4:first-child { margin-left: 34.04255319148936%; *margin-left: 33.93617021276596%; } - .row-fluid .offset3 { margin-left: 27.659574468085104%; *margin-left: 27.5531914893617%; } - .row-fluid .offset3:first-child { margin-left: 25.53191489361702%; *margin-left: 25.425531914893618%; } - .row-fluid .offset2 { margin-left: 19.148936170212764%; *margin-left: 19.04255319148936%; } - .row-fluid .offset2:first-child { margin-left: 17.02127659574468%; *margin-left: 16.914893617021278%; } - .row-fluid .offset1 { margin-left: 10.638297872340425%; *margin-left: 10.53191489361702%; } - .row-fluid .offset1:first-child { margin-left: 8.51063829787234%; *margin-left: 8.404255319148938%; } - [class*="span"].hide, .row-fluid [class*="span"].hide { display: none; } - [class*="span"].pull-right, .row-fluid [class*="span"].pull-right { float: right; } - .container { margin-right: auto; margin-left: auto; *zoom: 1; } - .container:before, .container:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .container:after { clear: both; } - .container-fluid { padding-right: 20px; padding-left: 20px; *zoom: 1; } - .container-fluid:before, .container-fluid:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .container-fluid:after { clear: both; } - p { - margin: 0 0 10px; + margin: 0 0 10.5px; } - .lead { - margin-bottom: 20px; + margin-bottom: 21px; font-size: 21px; font-weight: 200; - line-height: 30px; + line-height: 31.5px; } - small { font-size: 85%; } - strong { font-weight: bold; } - em { font-style: italic; } - cite { font-style: normal; } - .muted { - color: #999999; + color: #bbbbbb; } - .text-warning { - color: #c09853; + color: #ffffff; } - .text-error { - color: #b94a48; + color: #ffffff; } - .text-info { - color: #3a87ad; + color: #ffffff; } - .text-success { - color: #468847; + color: #ffffff; } - h1, h2, h3, h4, h5, h6 { - margin: 10px 0; + margin: 10.5px 0; font-family: inherit; - font-weight: bold; + font-weight: normal; line-height: 1; color: inherit; text-rendering: optimizelegibility; } - h1 small, h2 small, h3 small, @@ -648,170 +537,138 @@ h5 small, h6 small { font-weight: normal; line-height: 1; - color: #999999; + color: #bbbbbb; } - h1 { font-size: 36px; line-height: 40px; } - h2 { font-size: 30px; line-height: 40px; } - h3 { font-size: 24px; line-height: 40px; } - h4 { font-size: 18px; line-height: 20px; } - h5 { font-size: 14px; line-height: 20px; } - h6 { font-size: 12px; line-height: 20px; } - h1 small { font-size: 24px; } - h2 small { font-size: 18px; } - h3 small { font-size: 14px; } - h4 small { font-size: 14px; } - .page-header { - padding-bottom: 9px; - margin: 20px 0 30px; + padding-bottom: 9.5px; + margin: 21px 0 31.5px; border-bottom: 1px solid #eeeeee; } - ul, ol { padding: 0; - margin: 0 0 10px 25px; + margin: 0 0 10.5px 25px; } - ul ul, ul ol, ol ol, ol ul { margin-bottom: 0; } - li { - line-height: 20px; + line-height: 21px; } - ul.unstyled, ol.unstyled { margin-left: 0; list-style: none; } - dl { - margin-bottom: 20px; + margin-bottom: 21px; } - dt, dd { - line-height: 20px; + line-height: 21px; } - dt { font-weight: bold; } - dd { - margin-left: 10px; + margin-left: 10.5px; } - .dl-horizontal { *zoom: 1; } - .dl-horizontal:before, .dl-horizontal:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .dl-horizontal:after { clear: both; } - .dl-horizontal dt { float: left; width: 160px; - overflow: hidden; clear: left; text-align: right; + overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } - .dl-horizontal dd { margin-left: 180px; } - hr { - margin: 20px 0; + margin: 21px 0; border: 0; border-top: 1px solid #eeeeee; border-bottom: 1px solid #ffffff; } - abbr[title] { cursor: help; - border-bottom: 1px dotted #999999; + border-bottom: 1px dotted #bbbbbb; } - abbr.initialism { font-size: 90%; text-transform: uppercase; } - blockquote { padding: 0 0 0 15px; - margin: 0 0 20px; + margin: 0 0 21px; border-left: 5px solid #eeeeee; } - blockquote p { margin-bottom: 0; font-size: 16px; font-weight: 300; - line-height: 25px; + line-height: 26.25px; } - blockquote small { display: block; - line-height: 20px; - color: #999999; + line-height: 21px; + color: #bbbbbb; } - blockquote small:before { content: '\2014 \00A0'; } - blockquote.pull-right { float: right; padding-right: 15px; @@ -819,58 +676,50 @@ blockquote.pull-right { border-right: 5px solid #eeeeee; border-left: 0; } - blockquote.pull-right p, blockquote.pull-right small { text-align: right; } - blockquote.pull-right small:before { content: ''; } - blockquote.pull-right small:after { content: '\00A0 \2014'; } - q:before, q:after, blockquote:before, blockquote:after { content: ""; } - address { display: block; - margin-bottom: 20px; + margin-bottom: 21px; font-style: normal; - line-height: 20px; + line-height: 21px; } - code, pre { padding: 0 3px 2px; - font-family: Monaco, Menlo, Consolas, "Courier New", monospace; + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 12px; color: #333333; -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } - code { padding: 2px 4px; color: #d14; background-color: #f7f7f9; border: 1px solid #e1e1e8; } - pre { display: block; - padding: 9.5px; - margin: 0 0 10px; + padding: 10px; + margin: 0 0 10.5px; font-size: 13px; - line-height: 20px; + line-height: 21px; word-break: break-all; word-wrap: break-word; white-space: pre; @@ -879,53 +728,45 @@ pre { border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.15); -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; } - pre.prettyprint { - margin-bottom: 20px; + margin-bottom: 21px; } - pre code { padding: 0; color: inherit; background-color: transparent; border: 0; } - .pre-scrollable { max-height: 340px; overflow-y: scroll; } - form { - margin: 0 0 20px; + margin: 0 0 21px; } - fieldset { padding: 0; margin: 0; border: 0; } - legend { display: block; width: 100%; padding: 0; - margin-bottom: 20px; + margin-bottom: 21px; font-size: 21px; - line-height: 40px; + line-height: 42px; color: #333333; border: 0; border-bottom: 1px solid #e5e5e5; } - legend small { - font-size: 15px; - color: #999999; + font-size: 15.75px; + color: #bbbbbb; } - label, input, button, @@ -933,21 +774,18 @@ select, textarea { font-size: 14px; font-weight: normal; - line-height: 20px; + line-height: 21px; } - input, button, select, textarea { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-family: "Muli", "Helvetica Neue", Helvetica, Arial, sans-serif; } - label { display: block; margin-bottom: 5px; } - select, textarea, input[type="text"], @@ -966,27 +804,24 @@ input[type="tel"], input[type="color"], .uneditable-input { display: inline-block; - height: 20px; + height: 21px; padding: 4px 6px; margin-bottom: 9px; font-size: 14px; - line-height: 20px; - color: #555555; + line-height: 21px; + color: #777777; -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } - input, textarea, .uneditable-input { width: 206px; } - textarea { height: auto; } - textarea, input[type="text"], input[type="password"], @@ -1006,14 +841,13 @@ input[type="color"], background-color: #ffffff; border: 1px solid #cccccc; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; - -moz-transition: border linear 0.2s, box-shadow linear 0.2s; - -o-transition: border linear 0.2s, box-shadow linear 0.2s; - transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear .2s, box-shadow linear .2s; + -moz-transition: border linear .2s, box-shadow linear .2s; + -o-transition: border linear .2s, box-shadow linear .2s; + transition: border linear .2s, box-shadow linear .2s; } - textarea:focus, input[type="text"]:focus, input[type="password"]:focus, @@ -1036,19 +870,21 @@ input[type="color"]:focus, /* IE6-9 */ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); } - input[type="radio"], input[type="checkbox"] { margin: 4px 0 0; - margin-top: 1px \9; *margin-top: 0; + /* IE7 */ + + margin-top: 1px \9; + /* IE8-9 */ + line-height: normal; cursor: pointer; } - input[type="file"], input[type="image"], input[type="submit"], @@ -1058,7 +894,6 @@ input[type="radio"], input[type="checkbox"] { width: auto; } - select, input[type="file"] { height: 30px; @@ -1069,18 +904,15 @@ input[type="file"] { line-height: 30px; } - select { width: 220px; - background-color: #ffffff; border: 1px solid #cccccc; + background-color: #ffffff; } - select[multiple], select[size] { height: auto; } - select:focus, input[type="file"]:focus, input[type="radio"]:focus, @@ -1089,60 +921,50 @@ input[type="checkbox"]:focus { outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } - .uneditable-input, .uneditable-textarea { - color: #999999; - cursor: not-allowed; + color: #bbbbbb; background-color: #fcfcfc; border-color: #cccccc; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); - -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + cursor: not-allowed; } - .uneditable-input { overflow: hidden; white-space: nowrap; } - .uneditable-textarea { width: auto; height: auto; } - input:-moz-placeholder, textarea:-moz-placeholder { - color: #999999; + color: #bbbbbb; } - input:-ms-input-placeholder, textarea:-ms-input-placeholder { - color: #999999; + color: #bbbbbb; } - input::-webkit-input-placeholder, textarea::-webkit-input-placeholder { - color: #999999; + color: #bbbbbb; } - .radio, .checkbox { min-height: 18px; padding-left: 18px; } - .radio input[type="radio"], .checkbox input[type="checkbox"] { float: left; margin-left: -18px; } - .controls > .radio:first-child, .controls > .checkbox:first-child { padding-top: 5px; } - .radio.inline, .checkbox.inline { display: inline-block; @@ -1150,36 +972,28 @@ textarea::-webkit-input-placeholder { margin-bottom: 0; vertical-align: middle; } - .radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { margin-left: 10px; } - .input-mini { width: 60px; } - .input-small { width: 90px; } - .input-medium { width: 150px; } - .input-large { width: 210px; } - .input-xlarge { width: 270px; } - .input-xxlarge { width: 530px; } - input[class*="span"], select[class*="span"], textarea[class*="span"], @@ -1191,7 +1005,6 @@ textarea[class*="span"], float: none; margin-left: 0; } - .input-append input[class*="span"], .input-append .uneditable-input[class*="span"], .input-prepend input[class*="span"], @@ -1204,108 +1017,65 @@ textarea[class*="span"], .row-fluid .input-append [class*="span"] { display: inline-block; } - input, textarea, .uneditable-input { margin-left: 0; } - .controls-row [class*="span"] + [class*="span"] { margin-left: 20px; } - -input.span12, -textarea.span12, -.uneditable-input.span12 { +input.span12, textarea.span12, .uneditable-input.span12 { width: 926px; } - -input.span11, -textarea.span11, -.uneditable-input.span11 { +input.span11, textarea.span11, .uneditable-input.span11 { width: 846px; } - -input.span10, -textarea.span10, -.uneditable-input.span10 { +input.span10, textarea.span10, .uneditable-input.span10 { width: 766px; } - -input.span9, -textarea.span9, -.uneditable-input.span9 { +input.span9, textarea.span9, .uneditable-input.span9 { width: 686px; } - -input.span8, -textarea.span8, -.uneditable-input.span8 { +input.span8, textarea.span8, .uneditable-input.span8 { width: 606px; } - -input.span7, -textarea.span7, -.uneditable-input.span7 { +input.span7, textarea.span7, .uneditable-input.span7 { width: 526px; } - -input.span6, -textarea.span6, -.uneditable-input.span6 { +input.span6, textarea.span6, .uneditable-input.span6 { width: 446px; } - -input.span5, -textarea.span5, -.uneditable-input.span5 { +input.span5, textarea.span5, .uneditable-input.span5 { width: 366px; } - -input.span4, -textarea.span4, -.uneditable-input.span4 { +input.span4, textarea.span4, .uneditable-input.span4 { width: 286px; } - -input.span3, -textarea.span3, -.uneditable-input.span3 { +input.span3, textarea.span3, .uneditable-input.span3 { width: 206px; } - -input.span2, -textarea.span2, -.uneditable-input.span2 { +input.span2, textarea.span2, .uneditable-input.span2 { width: 126px; } - -input.span1, -textarea.span1, -.uneditable-input.span1 { +input.span1, textarea.span1, .uneditable-input.span1 { width: 46px; } - .controls-row { *zoom: 1; } - .controls-row:before, .controls-row:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .controls-row:after { clear: both; } - .controls-row [class*="span"] { float: left; } - input[disabled], select[disabled], textarea[disabled], @@ -1315,231 +1085,202 @@ textarea[readonly] { cursor: not-allowed; background-color: #eeeeee; } - input[type="radio"][disabled], input[type="checkbox"][disabled], input[type="radio"][readonly], input[type="checkbox"][readonly] { background-color: transparent; } - .control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { - color: #c09853; + color: #ffffff; } - .control-group.warning .checkbox, .control-group.warning .radio, .control-group.warning input, .control-group.warning select, .control-group.warning textarea { - color: #c09853; + color: #ffffff; } - .control-group.warning input, .control-group.warning select, .control-group.warning textarea { - border-color: #c09853; + border-color: #ffffff; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } - .control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { - border-color: #a47e3c; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + border-color: #e6e6e6; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; } - .control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { - color: #c09853; - background-color: #fcf8e3; - border-color: #c09853; + color: #ffffff; + background-color: #d47500; + border-color: #ffffff; } - .control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { - color: #b94a48; + color: #ffffff; } - .control-group.error .checkbox, .control-group.error .radio, .control-group.error input, .control-group.error select, .control-group.error textarea { - color: #b94a48; + color: #ffffff; } - .control-group.error input, .control-group.error select, .control-group.error textarea { - border-color: #b94a48; + border-color: #ffffff; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } - .control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { - border-color: #953b39; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + border-color: #e6e6e6; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; } - .control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { - color: #b94a48; - background-color: #f2dede; - border-color: #b94a48; + color: #ffffff; + background-color: #cd0200; + border-color: #ffffff; } - .control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { - color: #468847; + color: #ffffff; } - .control-group.success .checkbox, .control-group.success .radio, .control-group.success input, .control-group.success select, .control-group.success textarea { - color: #468847; + color: #ffffff; } - .control-group.success input, .control-group.success select, .control-group.success textarea { - border-color: #468847; + border-color: #ffffff; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } - .control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { - border-color: #356635; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + border-color: #e6e6e6; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; } - .control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { - color: #468847; - background-color: #dff0d8; - border-color: #468847; + color: #ffffff; + background-color: #819e37; + border-color: #ffffff; } - .control-group.info > label, .control-group.info .help-block, .control-group.info .help-inline { - color: #3a87ad; + color: #ffffff; } - .control-group.info .checkbox, .control-group.info .radio, .control-group.info input, .control-group.info select, .control-group.info textarea { - color: #3a87ad; + color: #ffffff; } - .control-group.info input, .control-group.info select, .control-group.info textarea { - border-color: #3a87ad; + border-color: #ffffff; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } - .control-group.info input:focus, .control-group.info select:focus, .control-group.info textarea:focus { - border-color: #2d6987; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + border-color: #e6e6e6; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; } - .control-group.info .input-prepend .add-on, .control-group.info .input-append .add-on { - color: #3a87ad; - background-color: #d9edf7; - border-color: #3a87ad; + color: #ffffff; + background-color: #3399f3; + border-color: #ffffff; } - input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { color: #b94a48; border-color: #ee5f5b; } - input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { border-color: #e9322d; -webkit-box-shadow: 0 0 6px #f8b9b7; - -moz-box-shadow: 0 0 6px #f8b9b7; - box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; } - .form-actions { - padding: 19px 20px 20px; - margin-top: 20px; - margin-bottom: 20px; + padding: 20px 20px 21px; + margin-top: 21px; + margin-bottom: 21px; background-color: #f5f5f5; border-top: 1px solid #e5e5e5; *zoom: 1; } - .form-actions:before, .form-actions:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .form-actions:after { clear: both; } - .help-block, .help-inline { - color: #595959; + color: #535353; } - .help-block { display: block; - margin-bottom: 10px; + margin-bottom: 10.5px; } - .help-inline { display: inline-block; *display: inline; - padding-left: 5px; - vertical-align: middle; - *zoom: 1; -} + /* IE7 inline-block hack */ + *zoom: 1; + vertical-align: middle; + padding-left: 5px; +} .input-append, .input-prepend { margin-bottom: 5px; font-size: 0; white-space: nowrap; } - .input-append input, .input-prepend input, .input-append select, @@ -1552,10 +1293,9 @@ select:focus:required:invalid:focus { font-size: 14px; vertical-align: top; -webkit-border-radius: 0 3px 3px 0; - -moz-border-radius: 0 3px 3px 0; - border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; } - .input-append input:focus, .input-prepend input:focus, .input-append select:focus, @@ -1564,95 +1304,83 @@ select:focus:required:invalid:focus { .input-prepend .uneditable-input:focus { z-index: 2; } - .input-append .add-on, .input-prepend .add-on { display: inline-block; width: auto; - height: 20px; + height: 21px; min-width: 16px; padding: 4px 5px; font-size: 14px; font-weight: normal; - line-height: 20px; + line-height: 21px; text-align: center; text-shadow: 0 1px 0 #ffffff; background-color: #eeeeee; border: 1px solid #ccc; } - .input-append .add-on, .input-prepend .add-on, .input-append .btn, .input-prepend .btn { vertical-align: top; -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; } - .input-append .active, .input-prepend .active { - background-color: #a9dba9; - border-color: #46a546; + background-color: #c6da94; + border-color: #819e37; } - .input-prepend .add-on, .input-prepend .btn { margin-right: -1px; } - .input-prepend .add-on:first-child, .input-prepend .btn:first-child { -webkit-border-radius: 3px 0 0 3px; - -moz-border-radius: 3px 0 0 3px; - border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; } - .input-append input, .input-append select, .input-append .uneditable-input { -webkit-border-radius: 3px 0 0 3px; - -moz-border-radius: 3px 0 0 3px; - border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; } - .input-append .add-on, .input-append .btn { margin-left: -1px; } - .input-append .add-on:last-child, .input-append .btn:last-child { -webkit-border-radius: 0 3px 3px 0; - -moz-border-radius: 0 3px 3px 0; - border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; } - .input-prepend.input-append input, .input-prepend.input-append select, .input-prepend.input-append .uneditable-input { -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; } - .input-prepend.input-append .add-on:first-child, .input-prepend.input-append .btn:first-child { margin-right: -1px; -webkit-border-radius: 3px 0 0 3px; - -moz-border-radius: 3px 0 0 3px; - border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; } - .input-prepend.input-append .add-on:last-child, .input-prepend.input-append .btn:last-child { margin-left: -1px; -webkit-border-radius: 0 3px 3px 0; - -moz-border-radius: 0 3px 3px 0; - border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; } - input.search-query { padding-right: 14px; padding-right: 4px \9; @@ -1662,43 +1390,36 @@ input.search-query { margin-bottom: 0; -webkit-border-radius: 15px; - -moz-border-radius: 15px; - border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; } - /* Allow for input prepend/append in search forms */ - .form-search .input-append .search-query, .form-search .input-prepend .search-query { -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; } - .form-search .input-append .search-query { -webkit-border-radius: 14px 0 0 14px; - -moz-border-radius: 14px 0 0 14px; - border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; } - .form-search .input-append .btn { -webkit-border-radius: 0 14px 14px 0; - -moz-border-radius: 0 14px 14px 0; - border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; } - .form-search .input-prepend .search-query { -webkit-border-radius: 0 14px 14px 0; - -moz-border-radius: 0 14px 14px 0; - border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; } - .form-search .input-prepend .btn { -webkit-border-radius: 14px 0 0 14px; - -moz-border-radius: 14px 0 0 14px; - border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; } - .form-search input, .form-inline input, .form-horizontal input, @@ -1722,31 +1443,29 @@ input.search-query { .form-horizontal .input-append { display: inline-block; *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; margin-bottom: 0; vertical-align: middle; - *zoom: 1; } - .form-search .hide, .form-inline .hide, .form-horizontal .hide { display: none; } - .form-search label, .form-inline label, .form-search .btn-group, .form-inline .btn-group { display: inline-block; } - .form-search .input-append, .form-inline .input-append, .form-search .input-prepend, .form-inline .input-prepend { margin-bottom: 0; } - .form-search .radio, .form-search .checkbox, .form-inline .radio, @@ -1755,7 +1474,6 @@ input.search-query { margin-bottom: 0; vertical-align: middle; } - .form-search .radio input[type="radio"], .form-search .checkbox input[type="checkbox"], .form-inline .radio input[type="radio"], @@ -1764,93 +1482,76 @@ input.search-query { margin-right: 3px; margin-left: 0; } - .control-group { - margin-bottom: 10px; + margin-bottom: 10.5px; } - legend + .control-group { - margin-top: 20px; + margin-top: 21px; -webkit-margin-top-collapse: separate; } - .form-horizontal .control-group { - margin-bottom: 20px; + margin-bottom: 21px; *zoom: 1; } - .form-horizontal .control-group:before, .form-horizontal .control-group:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .form-horizontal .control-group:after { clear: both; } - .form-horizontal .control-label { float: left; width: 160px; padding-top: 5px; text-align: right; } - .form-horizontal .controls { *display: inline-block; *padding-left: 20px; margin-left: 180px; *margin-left: 0; } - .form-horizontal .controls:first-child { *padding-left: 180px; } - .form-horizontal .help-block { margin-bottom: 0; } - .form-horizontal input + .help-block, .form-horizontal select + .help-block, .form-horizontal textarea + .help-block { - margin-top: 10px; + margin-top: 10.5px; } - .form-horizontal .form-actions { padding-left: 180px; } - table { max-width: 100%; background-color: transparent; border-collapse: collapse; border-spacing: 0; } - .table { width: 100%; - margin-bottom: 20px; + margin-bottom: 21px; } - .table th, .table td { padding: 8px; - line-height: 20px; + line-height: 21px; text-align: left; vertical-align: top; border-top: 1px solid #dddddd; } - .table th { font-weight: bold; } - .table thead th { vertical-align: bottom; } - .table caption + thead tr:first-child th, .table caption + thead tr:first-child td, .table colgroup + thead tr:first-child th, @@ -1859,31 +1560,26 @@ table { .table thead:first-child tr:first-child td { border-top: 0; } - .table tbody + tbody { border-top: 2px solid #dddddd; } - .table-condensed th, .table-condensed td { padding: 4px 5px; } - .table-bordered { border: 1px solid #dddddd; border-collapse: separate; *border-collapse: collapse; border-left: 0; -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; } - .table-bordered th, .table-bordered td { border-left: 1px solid #dddddd; } - .table-bordered caption + thead tr:first-child th, .table-bordered caption + tbody tr:first-child th, .table-bordered caption + tbody tr:first-child td, @@ -1895,267 +1591,223 @@ table { .table-bordered tbody:first-child tr:first-child td { border-top: 0; } - .table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { -webkit-border-top-left-radius: 4px; - border-top-left-radius: 4px; + border-top-left-radius: 4px; -moz-border-radius-topleft: 4px; } - .table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; + border-top-right-radius: 4px; -moz-border-radius-topright: 4px; } - .table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child, .table-bordered tfoot:last-child tr:last-child td:first-child { -webkit-border-radius: 0 0 0 4px; - -moz-border-radius: 0 0 0 4px; - border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; -webkit-border-bottom-left-radius: 4px; - border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; -moz-border-radius-bottomleft: 4px; } - .table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child, .table-bordered tfoot:last-child tr:last-child td:last-child { -webkit-border-bottom-right-radius: 4px; - border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; -moz-border-radius-bottomright: 4px; } - .table-bordered caption + thead tr:first-child th:first-child, .table-bordered caption + tbody tr:first-child td:first-child, .table-bordered colgroup + thead tr:first-child th:first-child, .table-bordered colgroup + tbody tr:first-child td:first-child { -webkit-border-top-left-radius: 4px; - border-top-left-radius: 4px; + border-top-left-radius: 4px; -moz-border-radius-topleft: 4px; } - .table-bordered caption + thead tr:first-child th:last-child, .table-bordered caption + tbody tr:first-child td:last-child, .table-bordered colgroup + thead tr:first-child th:last-child, .table-bordered colgroup + tbody tr:first-child td:last-child { -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; + border-top-right-radius: 4px; -moz-border-radius-topleft: 4px; } - .table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { background-color: #f9f9f9; } - .table-hover tbody tr:hover td, .table-hover tbody tr:hover th { background-color: #f5f5f5; } - table [class*=span], .row-fluid table [class*=span] { display: table-cell; float: none; margin-left: 0; } - .table .span1 { float: none; width: 44px; margin-left: 0; } - .table .span2 { float: none; width: 124px; margin-left: 0; } - .table .span3 { float: none; width: 204px; margin-left: 0; } - .table .span4 { float: none; width: 284px; margin-left: 0; } - .table .span5 { float: none; width: 364px; margin-left: 0; } - .table .span6 { float: none; width: 444px; margin-left: 0; } - .table .span7 { float: none; width: 524px; margin-left: 0; } - .table .span8 { float: none; width: 604px; margin-left: 0; } - .table .span9 { float: none; width: 684px; margin-left: 0; } - .table .span10 { float: none; width: 764px; margin-left: 0; } - .table .span11 { float: none; width: 844px; margin-left: 0; } - .table .span12 { float: none; width: 924px; margin-left: 0; } - .table .span13 { float: none; width: 1004px; margin-left: 0; } - .table .span14 { float: none; width: 1084px; margin-left: 0; } - .table .span15 { float: none; width: 1164px; margin-left: 0; } - .table .span16 { float: none; width: 1244px; margin-left: 0; } - .table .span17 { float: none; width: 1324px; margin-left: 0; } - .table .span18 { float: none; width: 1404px; margin-left: 0; } - .table .span19 { float: none; width: 1484px; margin-left: 0; } - .table .span20 { float: none; width: 1564px; margin-left: 0; } - .table .span21 { float: none; width: 1644px; margin-left: 0; } - .table .span22 { float: none; width: 1724px; margin-left: 0; } - .table .span23 { float: none; width: 1804px; margin-left: 0; } - .table .span24 { float: none; width: 1884px; margin-left: 0; } - .table tbody tr.success td { - background-color: #dff0d8; + background-color: #819e37; } - .table tbody tr.error td { - background-color: #f2dede; + background-color: #cd0200; } - .table tbody tr.warning td { - background-color: #fcf8e3; + background-color: #d47500; } - .table tbody tr.info td { - background-color: #d9edf7; + background-color: #3399f3; } - .table-hover tbody tr.success:hover td { - background-color: #d0e9c6; + background-color: #728b30; } - .table-hover tbody tr.error:hover td { - background-color: #ebcccc; + background-color: #b40200; } - .table-hover tbody tr.warning:hover td { - background-color: #faf2cc; + background-color: #bb6700; } - .table-hover tbody tr.info:hover td { - background-color: #c4e3f3; + background-color: #1b8df2; } - [class^="icon-"], [class*=" icon-"] { display: inline-block; width: 14px; height: 14px; - margin-top: 1px; *margin-right: .3em; line-height: 14px; vertical-align: text-top; background-image: url("../img/glyphicons-halflings.png"); background-position: 14px 14px; background-repeat: no-repeat; + margin-top: 1px; } - /* White icons with optional class, or on hover/active states of certain elements */ - .icon-white, .nav-tabs > .active > a > [class^="icon-"], .nav-tabs > .active > a > [class*=" icon-"], @@ -2171,583 +1823,439 @@ table [class*=span], .dropdown-menu > .active > a > [class*=" icon-"] { background-image: url("../img/glyphicons-halflings-white.png"); } - .icon-glass { background-position: 0 0; } - .icon-music { background-position: -24px 0; } - .icon-search { background-position: -48px 0; } - .icon-envelope { background-position: -72px 0; } - .icon-heart { background-position: -96px 0; } - .icon-star { background-position: -120px 0; } - .icon-star-empty { background-position: -144px 0; } - .icon-user { background-position: -168px 0; } - .icon-film { background-position: -192px 0; } - .icon-th-large { background-position: -216px 0; } - .icon-th { background-position: -240px 0; } - .icon-th-list { background-position: -264px 0; } - .icon-ok { background-position: -288px 0; } - .icon-remove { background-position: -312px 0; } - .icon-zoom-in { background-position: -336px 0; } - .icon-zoom-out { background-position: -360px 0; } - .icon-off { background-position: -384px 0; } - .icon-signal { background-position: -408px 0; } - .icon-cog { background-position: -432px 0; } - .icon-trash { background-position: -456px 0; } - .icon-home { background-position: 0 -24px; } - .icon-file { background-position: -24px -24px; } - .icon-time { background-position: -48px -24px; } - .icon-road { background-position: -72px -24px; } - .icon-download-alt { background-position: -96px -24px; } - .icon-download { background-position: -120px -24px; } - .icon-upload { background-position: -144px -24px; } - .icon-inbox { background-position: -168px -24px; } - .icon-play-circle { background-position: -192px -24px; } - .icon-repeat { background-position: -216px -24px; } - .icon-refresh { background-position: -240px -24px; } - .icon-list-alt { background-position: -264px -24px; } - .icon-lock { background-position: -287px -24px; } - .icon-flag { background-position: -312px -24px; } - .icon-headphones { background-position: -336px -24px; } - .icon-volume-off { background-position: -360px -24px; } - .icon-volume-down { background-position: -384px -24px; } - .icon-volume-up { background-position: -408px -24px; } - .icon-qrcode { background-position: -432px -24px; } - .icon-barcode { background-position: -456px -24px; } - .icon-tag { background-position: 0 -48px; } - .icon-tags { background-position: -25px -48px; } - .icon-book { background-position: -48px -48px; } - .icon-bookmark { background-position: -72px -48px; } - .icon-print { background-position: -96px -48px; } - .icon-camera { background-position: -120px -48px; } - .icon-font { background-position: -144px -48px; } - .icon-bold { background-position: -167px -48px; } - .icon-italic { background-position: -192px -48px; } - .icon-text-height { background-position: -216px -48px; } - .icon-text-width { background-position: -240px -48px; } - .icon-align-left { background-position: -264px -48px; } - .icon-align-center { background-position: -288px -48px; } - .icon-align-right { background-position: -312px -48px; } - .icon-align-justify { background-position: -336px -48px; } - .icon-list { background-position: -360px -48px; } - .icon-indent-left { background-position: -384px -48px; } - .icon-indent-right { background-position: -408px -48px; } - .icon-facetime-video { background-position: -432px -48px; } - .icon-picture { background-position: -456px -48px; } - .icon-pencil { background-position: 0 -72px; } - .icon-map-marker { background-position: -24px -72px; } - .icon-adjust { background-position: -48px -72px; } - .icon-tint { background-position: -72px -72px; } - .icon-edit { background-position: -96px -72px; } - .icon-share { background-position: -120px -72px; } - .icon-check { background-position: -144px -72px; } - .icon-move { background-position: -168px -72px; } - .icon-step-backward { background-position: -192px -72px; } - .icon-fast-backward { background-position: -216px -72px; } - .icon-backward { background-position: -240px -72px; } - .icon-play { background-position: -264px -72px; } - .icon-pause { background-position: -288px -72px; } - .icon-stop { background-position: -312px -72px; } - .icon-forward { background-position: -336px -72px; } - .icon-fast-forward { background-position: -360px -72px; } - .icon-step-forward { background-position: -384px -72px; } - .icon-eject { background-position: -408px -72px; } - .icon-chevron-left { background-position: -432px -72px; } - .icon-chevron-right { background-position: -456px -72px; } - .icon-plus-sign { background-position: 0 -96px; } - .icon-minus-sign { background-position: -24px -96px; } - .icon-remove-sign { background-position: -48px -96px; } - .icon-ok-sign { background-position: -72px -96px; } - .icon-question-sign { background-position: -96px -96px; } - .icon-info-sign { background-position: -120px -96px; } - .icon-screenshot { background-position: -144px -96px; } - .icon-remove-circle { background-position: -168px -96px; } - .icon-ok-circle { background-position: -192px -96px; } - .icon-ban-circle { background-position: -216px -96px; } - .icon-arrow-left { background-position: -240px -96px; } - .icon-arrow-right { background-position: -264px -96px; } - .icon-arrow-up { background-position: -289px -96px; } - .icon-arrow-down { background-position: -312px -96px; } - .icon-share-alt { background-position: -336px -96px; } - .icon-resize-full { background-position: -360px -96px; } - .icon-resize-small { background-position: -384px -96px; } - .icon-plus { background-position: -408px -96px; } - .icon-minus { background-position: -433px -96px; } - .icon-asterisk { background-position: -456px -96px; } - .icon-exclamation-sign { background-position: 0 -120px; } - .icon-gift { background-position: -24px -120px; } - .icon-leaf { background-position: -48px -120px; } - .icon-fire { background-position: -72px -120px; } - .icon-eye-open { background-position: -96px -120px; } - .icon-eye-close { background-position: -120px -120px; } - .icon-warning-sign { background-position: -144px -120px; } - .icon-plane { background-position: -168px -120px; } - .icon-calendar { background-position: -192px -120px; } - .icon-random { - width: 16px; background-position: -216px -120px; + width: 16px; } - .icon-comment { background-position: -240px -120px; } - .icon-magnet { background-position: -264px -120px; } - .icon-chevron-up { background-position: -288px -120px; } - .icon-chevron-down { background-position: -313px -119px; } - .icon-retweet { background-position: -336px -120px; } - .icon-shopping-cart { background-position: -360px -120px; } - .icon-folder-close { background-position: -384px -120px; } - .icon-folder-open { - width: 16px; background-position: -408px -120px; + width: 16px; } - .icon-resize-vertical { background-position: -432px -119px; } - .icon-resize-horizontal { background-position: -456px -118px; } - .icon-hdd { background-position: 0 -144px; } - .icon-bullhorn { background-position: -24px -144px; } - .icon-bell { background-position: -48px -144px; } - .icon-certificate { background-position: -72px -144px; } - .icon-thumbs-up { background-position: -96px -144px; } - .icon-thumbs-down { background-position: -120px -144px; } - .icon-hand-right { background-position: -144px -144px; } - .icon-hand-left { background-position: -168px -144px; } - .icon-hand-up { background-position: -192px -144px; } - .icon-hand-down { background-position: -216px -144px; } - .icon-circle-arrow-right { background-position: -240px -144px; } - .icon-circle-arrow-left { background-position: -264px -144px; } - .icon-circle-arrow-up { background-position: -288px -144px; } - .icon-circle-arrow-down { background-position: -312px -144px; } - .icon-globe { background-position: -336px -144px; } - .icon-wrench { background-position: -360px -144px; } - .icon-tasks { background-position: -384px -144px; } - .icon-filter { background-position: -408px -144px; } - .icon-briefcase { background-position: -432px -144px; } - .icon-fullscreen { background-position: -456px -144px; } - .dropup, .dropdown { position: relative; } - .dropdown-toggle { *margin-bottom: -3px; } - .dropdown-toggle:active, .open .dropdown-toggle { outline: 0; } - .caret { display: inline-block; width: 0; @@ -2758,12 +2266,10 @@ table [class*=span], border-left: 4px solid transparent; content: ""; } - .dropdown .caret { margin-top: 8px; margin-left: 2px; } - .dropdown-menu { position: absolute; top: 100%; @@ -2781,159 +2287,139 @@ table [class*=span], *border-right-width: 2px; *border-bottom-width: 2px; -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); -webkit-background-clip: padding-box; - -moz-background-clip: padding; - background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; } - .dropdown-menu.pull-right { right: 0; left: auto; } - .dropdown-menu .divider { *width: 100%; height: 1px; - margin: 9px 1px; + margin: 9.5px 1px; *margin: -5px 0 5px; overflow: hidden; background-color: #e5e5e5; border-bottom: 1px solid #ffffff; } - .dropdown-menu a { display: block; padding: 3px 20px; clear: both; font-weight: normal; - line-height: 20px; - color: #333333; + line-height: 21px; + color: #2d2d2d; white-space: nowrap; } - .dropdown-menu li > a:hover, .dropdown-menu li > a:focus, .dropdown-submenu:hover > a { - color: #ffffff; text-decoration: none; - background-color: #0088cc; - background-color: #0081c2; - background-image: -moz-linear-gradient(top, #0088cc, #0077b3); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); - background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); - background-image: -o-linear-gradient(top, #0088cc, #0077b3); - background-image: linear-gradient(to bottom, #0088cc, #0077b3); + color: #ffffff; + background-color: #558bc4; + background-color: #4d86c1; + background-image: -moz-linear-gradient(top, #558bc4, #427ebd); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#558bc4), to(#427ebd)); + background-image: -webkit-linear-gradient(top, #558bc4, #427ebd); + background-image: -o-linear-gradient(top, #558bc4, #427ebd); + background-image: linear-gradient(to bottom, #558bc4, #427ebd); background-repeat: repeat-x; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff558bc4', endColorstr='#ff427ebd', GradientType=0); } - .dropdown-menu .active > a, .dropdown-menu .active > a:hover { color: #ffffff; text-decoration: none; - background-color: #0088cc; - background-color: #0081c2; - background-image: linear-gradient(to bottom, #0088cc, #0077b3); - background-image: -moz-linear-gradient(top, #0088cc, #0077b3); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); - background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); - background-image: -o-linear-gradient(top, #0088cc, #0077b3); - background-repeat: repeat-x; outline: 0; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); + background-color: #558bc4; + background-color: #4d86c1; + background-image: -moz-linear-gradient(top, #558bc4, #427ebd); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#558bc4), to(#427ebd)); + background-image: -webkit-linear-gradient(top, #558bc4, #427ebd); + background-image: -o-linear-gradient(top, #558bc4, #427ebd); + background-image: linear-gradient(to bottom, #558bc4, #427ebd); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff558bc4', endColorstr='#ff427ebd', GradientType=0); } - .dropdown-menu .disabled > a, .dropdown-menu .disabled > a:hover { - color: #999999; + color: #bbbbbb; } - .dropdown-menu .disabled > a:hover { text-decoration: none; - cursor: default; background-color: transparent; + cursor: default; } - .open { *z-index: 1000; } - -.open > .dropdown-menu { +.open > .dropdown-menu { display: block; } - .pull-right > .dropdown-menu { right: 0; left: auto; } - .dropup .caret, .navbar-fixed-bottom .dropdown .caret { border-top: 0; border-bottom: 4px solid #000000; content: ""; } - .dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .dropdown-menu { top: auto; bottom: 100%; margin-bottom: 1px; } - .dropdown-submenu { position: relative; } - .dropdown-submenu > .dropdown-menu { top: 0; left: 100%; margin-top: -6px; margin-left: -1px; -webkit-border-radius: 0 6px 6px 6px; - -moz-border-radius: 0 6px 6px 6px; - border-radius: 0 6px 6px 6px; + -moz-border-radius: 0 6px 6px 6px; + border-radius: 0 6px 6px 6px; } - .dropdown-submenu:hover > .dropdown-menu { display: block; } - .dropdown-submenu > a:after { display: block; + content: " "; float: right; width: 0; height: 0; - margin-top: 5px; - margin-right: -10px; border-color: transparent; - border-left-color: #cccccc; border-style: solid; border-width: 5px 0 5px 5px; - content: " "; + border-left-color: #cccccc; + margin-top: 5px; + margin-right: -10px; } - .dropdown-submenu:hover > a:after { border-left-color: #ffffff; } - .dropdown .dropdown-menu .nav-header { - padding-right: 20px; padding-left: 20px; + padding-right: 20px; } - .typeahead { margin-top: 2px; -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; } - .well { min-height: 20px; padding: 19px; @@ -2941,69 +2427,60 @@ table [class*=span], background-color: #f5f5f5; border: 1px solid #e3e3e3; -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); } - .well blockquote { border-color: #ddd; border-color: rgba(0, 0, 0, 0.15); } - .well-large { padding: 24px; -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; } - .well-small { padding: 9px; -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } - .fade { opacity: 0; -webkit-transition: opacity 0.15s linear; - -moz-transition: opacity 0.15s linear; - -o-transition: opacity 0.15s linear; - transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; } - .fade.in { opacity: 1; } - .collapse { position: relative; height: 0; overflow: hidden; -webkit-transition: height 0.35s ease; - -moz-transition: height 0.35s ease; - -o-transition: height 0.35s ease; - transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; } - .collapse.in { height: auto; } - .close { float: right; font-size: 20px; font-weight: bold; - line-height: 20px; + line-height: 21px; color: #000000; text-shadow: 0 1px 0 #ffffff; opacity: 0.2; filter: alpha(opacity=20); } - .close:hover { color: #000000; text-decoration: none; @@ -3011,7 +2488,6 @@ table [class*=span], opacity: 0.4; filter: alpha(opacity=40); } - button.close { padding: 0; cursor: pointer; @@ -3019,64 +2495,63 @@ button.close { border: 0; -webkit-appearance: none; } - .btn { display: inline-block; *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; padding: 4px 14px; margin-bottom: 0; - *margin-left: .3em; font-size: 14px; - line-height: 20px; - *line-height: 20px; - color: #333333; + line-height: 21px; + *line-height: 21px; text-align: center; - text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); vertical-align: middle; cursor: pointer; - background-color: #f5f5f5; - *background-color: #e6e6e6; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); - background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); - background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); - background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + color: #333333; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + background-color: #f8f8f8; + background-image: -moz-linear-gradient(top, #ffffff, #eeeeee); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#eeeeee)); + background-image: -webkit-linear-gradient(top, #ffffff, #eeeeee); + background-image: -o-linear-gradient(top, #ffffff, #eeeeee); + background-image: linear-gradient(to bottom, #ffffff, #eeeeee); background-repeat: repeat-x; - border: 1px solid #bbbbbb; - *border: 0; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffeeeeee', GradientType=0); + border-color: #eeeeee #eeeeee #c8c8c8; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - border-color: #e6e6e6 #e6e6e6 #bfbfbf; - border-bottom-color: #a2a2a2; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); - *zoom: 1; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -} + *background-color: #eeeeee; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #cccccc; + *border: 0; + border-bottom-color: #b3b3b3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + *margin-left: .3em; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} .btn:hover, .btn:active, .btn.active, .btn.disabled, .btn[disabled] { color: #333333; - background-color: #e6e6e6; - *background-color: #d9d9d9; + background-color: #eeeeee; + *background-color: #e1e1e1; } - .btn:active, .btn.active { - background-color: #cccccc \9; + background-color: #d5d5d5 \9; } - .btn:first-child { *margin-left: 0; } - .btn:hover { color: #333333; text-decoration: none; @@ -3086,17 +2561,15 @@ button.close { background-position: 0 -15px; -webkit-transition: background-position 0.1s linear; - -moz-transition: background-position 0.1s linear; - -o-transition: background-position 0.1s linear; - transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; } - .btn:focus { outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } - .btn.active, .btn:active { background-color: #e6e6e6; @@ -3104,10 +2577,9 @@ button.close { background-image: none; outline: 0; -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); } - .btn.disabled, .btn[disabled] { cursor: default; @@ -3116,59 +2588,50 @@ button.close { opacity: 0.65; filter: alpha(opacity=65); -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; } - .btn-large { padding: 9px 14px; font-size: 16px; line-height: normal; -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; } - .btn-large [class^="icon-"] { margin-top: 2px; } - .btn-small { padding: 3px 9px; font-size: 12px; - line-height: 18px; + line-height: 19px; } - .btn-small [class^="icon-"] { margin-top: 0; } - .btn-mini { padding: 2px 6px; font-size: 11px; - line-height: 17px; + line-height: 18px; } - .btn-block { display: block; width: 100%; - padding-right: 0; padding-left: 0; + padding-right: 0; -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } - .btn-block + .btn-block { margin-top: 5px; } - input[type="submit"].btn-block, input[type="reset"].btn-block, input[type="button"].btn-block { width: 100%; } - .btn-primary.active, .btn-warning.active, .btn-danger.active, @@ -3177,286 +2640,265 @@ input[type="button"].btn-block { .btn-inverse.active { color: rgba(255, 255, 255, 0.75); } - .btn { border-color: #c5c5c5; border-color: rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25); } - .btn-primary { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #006dcc; - *background-color: #0044cc; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); - background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); - background-image: -o-linear-gradient(top, #0088cc, #0044cc); - background-image: linear-gradient(to bottom, #0088cc, #0044cc); - background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-color: #77a2d0; + background-image: -moz-linear-gradient(top, #8eb2d8, #558bc4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#8eb2d8), to(#558bc4)); + background-image: -webkit-linear-gradient(top, #8eb2d8, #558bc4); + background-image: -o-linear-gradient(top, #8eb2d8, #558bc4); + background-image: linear-gradient(to bottom, #8eb2d8, #558bc4); background-repeat: repeat-x; - border-color: #0044cc #0044cc #002a80; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff8eb2d8', endColorstr='#ff558bc4', GradientType=0); + border-color: #558bc4 #558bc4 #356598; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); -} + *background-color: #558bc4; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} .btn-primary:hover, .btn-primary:active, .btn-primary.active, .btn-primary.disabled, .btn-primary[disabled] { color: #ffffff; - background-color: #0044cc; - *background-color: #003bb3; + background-color: #558bc4; + *background-color: #427ebd; } - .btn-primary:active, .btn-primary.active { - background-color: #003399 \9; + background-color: #3b71ab \9; } - .btn-warning { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #faa732; - *background-color: #f89406; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); - background-image: -webkit-linear-gradient(top, #fbb450, #f89406); - background-image: -o-linear-gradient(top, #fbb450, #f89406); - background-image: linear-gradient(to bottom, #fbb450, #f89406); - background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-color: #ee8c14; + background-image: -moz-linear-gradient(top, #ff9c21, #d47500); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ff9c21), to(#d47500)); + background-image: -webkit-linear-gradient(top, #ff9c21, #d47500); + background-image: -o-linear-gradient(top, #ff9c21, #d47500); + background-image: linear-gradient(to bottom, #ff9c21, #d47500); background-repeat: repeat-x; - border-color: #f89406 #f89406 #ad6704; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff9c21', endColorstr='#ffd47500', GradientType=0); + border-color: #d47500 #d47500 #884b00; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); -} + *background-color: #d47500; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} .btn-warning:hover, .btn-warning:active, .btn-warning.active, .btn-warning.disabled, .btn-warning[disabled] { color: #ffffff; - background-color: #f89406; - *background-color: #df8505; + background-color: #d47500; + *background-color: #bb6700; } - .btn-warning:active, .btn-warning.active { - background-color: #c67605 \9; + background-color: #a15900 \9; } - .btn-danger { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #da4f49; - *background-color: #bd362f; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); - background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); - background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); - background-image: linear-gradient(to bottom, #ee5f5b, #bd362f); - background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-color: #eb1210; + background-image: -moz-linear-gradient(top, #ff1d1b, #cd0200); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ff1d1b), to(#cd0200)); + background-image: -webkit-linear-gradient(top, #ff1d1b, #cd0200); + background-image: -o-linear-gradient(top, #ff1d1b, #cd0200); + background-image: linear-gradient(to bottom, #ff1d1b, #cd0200); background-repeat: repeat-x; - border-color: #bd362f #bd362f #802420; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff1d1b', endColorstr='#ffcd0200', GradientType=0); + border-color: #cd0200 #cd0200 #810100; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); -} + *background-color: #cd0200; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} .btn-danger:hover, .btn-danger:active, .btn-danger.active, .btn-danger.disabled, .btn-danger[disabled] { color: #ffffff; - background-color: #bd362f; - *background-color: #a9302a; + background-color: #cd0200; + *background-color: #b40200; } - .btn-danger:active, .btn-danger.active { - background-color: #942a25 \9; + background-color: #9a0200 \9; } - .btn-success { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #5bb75b; - *background-color: #51a351; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); - background-image: -webkit-linear-gradient(top, #62c462, #51a351); - background-image: -o-linear-gradient(top, #62c462, #51a351); - background-image: linear-gradient(to bottom, #62c462, #51a351); - background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-color: #98b64d; + background-image: -moz-linear-gradient(top, #a8c65b, #819e37); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#a8c65b), to(#819e37)); + background-image: -webkit-linear-gradient(top, #a8c65b, #819e37); + background-image: -o-linear-gradient(top, #a8c65b, #819e37); + background-image: linear-gradient(to bottom, #a8c65b, #819e37); background-repeat: repeat-x; - border-color: #51a351 #51a351 #387038; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa8c65b', endColorstr='#ff819e37', GradientType=0); + border-color: #819e37 #819e37 #536523; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); -} + *background-color: #819e37; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} .btn-success:hover, .btn-success:active, .btn-success.active, .btn-success.disabled, .btn-success[disabled] { color: #ffffff; - background-color: #51a351; - *background-color: #499249; + background-color: #819e37; + *background-color: #728b30; } - .btn-success:active, .btn-success.active { - background-color: #408140 \9; + background-color: #62782a \9; } - .btn-info { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #49afcd; - *background-color: #2f96b4; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); - background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); - background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); - background-image: linear-gradient(to bottom, #5bc0de, #2f96b4); - background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-color: #d2d2d2; + background-image: -moz-linear-gradient(top, #e1e1e1, #bbbbbb); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#e1e1e1), to(#bbbbbb)); + background-image: -webkit-linear-gradient(top, #e1e1e1, #bbbbbb); + background-image: -o-linear-gradient(top, #e1e1e1, #bbbbbb); + background-image: linear-gradient(to bottom, #e1e1e1, #bbbbbb); background-repeat: repeat-x; - border-color: #2f96b4 #2f96b4 #1f6377; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe1e1e1', endColorstr='#ffbbbbbb', GradientType=0); + border-color: #bbbbbb #bbbbbb #959595; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); -} + *background-color: #bbbbbb; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} .btn-info:hover, .btn-info:active, .btn-info.active, .btn-info.disabled, .btn-info[disabled] { color: #ffffff; - background-color: #2f96b4; - *background-color: #2a85a0; + background-color: #bbbbbb; + *background-color: #aeaeae; } - .btn-info:active, .btn-info.active { - background-color: #24748c \9; + background-color: #a2a2a2 \9; } - .btn-inverse { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #363636; - *background-color: #222222; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); - background-image: -webkit-linear-gradient(top, #444444, #222222); - background-image: -o-linear-gradient(top, #444444, #222222); - background-image: linear-gradient(to bottom, #444444, #222222); - background-image: -moz-linear-gradient(top, #444444, #222222); + background-color: #848a94; + background-image: -moz-linear-gradient(top, #949aa3, #6c737e); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#949aa3), to(#6c737e)); + background-image: -webkit-linear-gradient(top, #949aa3, #6c737e); + background-image: -o-linear-gradient(top, #949aa3, #6c737e); + background-image: linear-gradient(to bottom, #949aa3, #6c737e); background-repeat: repeat-x; - border-color: #222222 #222222 #000000; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff949aa3', endColorstr='#ff6c737e', GradientType=0); + border-color: #6c737e #6c737e #494d55; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); -} + *background-color: #6c737e; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} .btn-inverse:hover, .btn-inverse:active, .btn-inverse.active, .btn-inverse.disabled, .btn-inverse[disabled] { color: #ffffff; - background-color: #222222; - *background-color: #151515; + background-color: #6c737e; + *background-color: #606670; } - .btn-inverse:active, .btn-inverse.active { - background-color: #080808 \9; + background-color: #545a63 \9; } - button.btn, input[type="submit"].btn { *padding-top: 3px; *padding-bottom: 3px; } - button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { padding: 0; border: 0; } - button.btn.btn-large, input[type="submit"].btn.btn-large { *padding-top: 7px; *padding-bottom: 7px; } - button.btn.btn-small, input[type="submit"].btn.btn-small { *padding-top: 3px; *padding-bottom: 3px; } - button.btn.btn-mini, input[type="submit"].btn.btn-mini { *padding-top: 1px; *padding-bottom: 1px; } - .btn-link, .btn-link:active, .btn-link[disabled] { background-color: transparent; background-image: none; -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; } - .btn-link { - color: #0088cc; - cursor: pointer; border-color: transparent; + cursor: pointer; + color: #558bc4; -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; } - .btn-link:hover { - color: #005580; + color: #558bc4; text-decoration: underline; background-color: transparent; } - .btn-link[disabled]:hover { color: #333333; text-decoration: none; } - .btn-group { position: relative; - *margin-left: .3em; font-size: 0; - white-space: nowrap; vertical-align: middle; + white-space: nowrap; + *margin-left: .3em; } - .btn-group:first-child { *margin-left: 0; } - .btn-group + .btn-group { margin-left: 5px; } - .btn-toolbar { - margin-top: 10px; - margin-bottom: 10px; font-size: 0; + margin-top: 10.5px; + margin-bottom: 10.5px; } - .btn-toolbar .btn-group { display: inline-block; *display: inline; @@ -3464,179 +2906,149 @@ input[type="submit"].btn.btn-mini { *zoom: 1; } - .btn-toolbar .btn + .btn, .btn-toolbar .btn-group + .btn, .btn-toolbar .btn + .btn-group { margin-left: 5px; } - .btn-group > .btn { position: relative; -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; } - .btn-group > .btn + .btn { margin-left: -1px; } - .btn-group > .btn, .btn-group > .dropdown-menu { font-size: 14px; } - .btn-group > .btn-mini { font-size: 11px; } - .btn-group > .btn-small { font-size: 12px; } - .btn-group > .btn-large { font-size: 16px; } - .btn-group > .btn:first-child { margin-left: 0; - -webkit-border-bottom-left-radius: 4px; - border-bottom-left-radius: 4px; -webkit-border-top-left-radius: 4px; - border-top-left-radius: 4px; - -moz-border-radius-bottomleft: 4px; -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; } - .btn-group > .btn:last-child, .btn-group > .dropdown-toggle { -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; - -webkit-border-bottom-right-radius: 4px; - border-bottom-right-radius: 4px; -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; } - .btn-group > .btn.large:first-child { margin-left: 0; - -webkit-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; -webkit-border-top-left-radius: 6px; - border-top-left-radius: 6px; - -moz-border-radius-bottomleft: 6px; -moz-border-radius-topleft: 6px; + border-top-left-radius: 6px; + -webkit-border-bottom-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + border-bottom-left-radius: 6px; } - .btn-group > .btn.large:last-child, .btn-group > .large.dropdown-toggle { -webkit-border-top-right-radius: 6px; - border-top-right-radius: 6px; - -webkit-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; -moz-border-radius-topright: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; -moz-border-radius-bottomright: 6px; + border-bottom-right-radius: 6px; } - .btn-group > .btn:hover, .btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active { z-index: 2; } - .btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { outline: 0; } - .btn-group > .btn + .dropdown-toggle { - *padding-top: 5px; - padding-right: 8px; - *padding-bottom: 5px; padding-left: 8px; + padding-right: 8px; -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + *padding-top: 5px; + *padding-bottom: 5px; } - .btn-group > .btn-mini + .dropdown-toggle { - *padding-top: 2px; - padding-right: 5px; - *padding-bottom: 2px; padding-left: 5px; + padding-right: 5px; + *padding-top: 2px; + *padding-bottom: 2px; } - .btn-group > .btn-small + .dropdown-toggle { *padding-top: 5px; *padding-bottom: 4px; } - .btn-group > .btn-large + .dropdown-toggle { - *padding-top: 7px; - padding-right: 12px; - *padding-bottom: 7px; padding-left: 12px; + padding-right: 12px; + *padding-top: 7px; + *padding-bottom: 7px; } - .btn-group.open .dropdown-toggle { background-image: none; -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); } - .btn-group.open .btn.dropdown-toggle { - background-color: #e6e6e6; + background-color: #eeeeee; } - .btn-group.open .btn-primary.dropdown-toggle { - background-color: #0044cc; + background-color: #558bc4; } - .btn-group.open .btn-warning.dropdown-toggle { - background-color: #f89406; + background-color: #d47500; } - .btn-group.open .btn-danger.dropdown-toggle { - background-color: #bd362f; + background-color: #cd0200; } - .btn-group.open .btn-success.dropdown-toggle { - background-color: #51a351; + background-color: #819e37; } - .btn-group.open .btn-info.dropdown-toggle { - background-color: #2f96b4; + background-color: #bbbbbb; } - .btn-group.open .btn-inverse.dropdown-toggle { - background-color: #222222; + background-color: #6c737e; } - .btn .caret { margin-top: 8px; margin-left: 0; } - .btn-mini .caret, .btn-small .caret, .btn-large .caret { margin-top: 6px; } - .btn-large .caret { - border-top-width: 5px; - border-right-width: 5px; border-left-width: 5px; + border-right-width: 5px; + border-top-width: 5px; } - .dropup .btn-large .caret { - border-top: 0; border-bottom: 5px solid #000000; + border-top: 0; } - .btn-primary .caret, .btn-warning .caret, .btn-danger .caret, @@ -3646,7 +3058,6 @@ input[type="submit"].btn.btn-mini { border-top-color: #ffffff; border-bottom-color: #ffffff; } - .btn-group-vertical { display: inline-block; *display: inline; @@ -3654,197 +3065,165 @@ input[type="submit"].btn.btn-mini { *zoom: 1; } - .btn-group-vertical .btn { display: block; float: none; width: 100%; -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; } - .btn-group-vertical .btn + .btn { - margin-top: -1px; margin-left: 0; + margin-top: -1px; } - .btn-group-vertical .btn:first-child { -webkit-border-radius: 4px 4px 0 0; - -moz-border-radius: 4px 4px 0 0; - border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; } - .btn-group-vertical .btn:last-child { -webkit-border-radius: 0 0 4px 4px; - -moz-border-radius: 0 0 4px 4px; - border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; } - .btn-group-vertical .btn-large:first-child { -webkit-border-radius: 6px 6px 0 0; - -moz-border-radius: 6px 6px 0 0; - border-radius: 6px 6px 0 0; + -moz-border-radius: 6px 6px 0 0; + border-radius: 6px 6px 0 0; } - .btn-group-vertical .btn-large:last-child { -webkit-border-radius: 0 0 6px 6px; - -moz-border-radius: 0 0 6px 6px; - border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; } - .alert { padding: 8px 35px 8px 14px; - margin-bottom: 20px; - color: #c09853; + margin-bottom: 21px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); - background-color: #fcf8e3; - border: 1px solid #fbeed5; + background-color: #d47500; + border: 1px solid #c54c00; -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + color: #ffffff; } - .alert h4 { margin: 0; } - .alert .close { position: relative; top: -2px; right: -21px; - line-height: 20px; + line-height: 21px; } - .alert-success { - color: #468847; - background-color: #dff0d8; - border-color: #d6e9c6; + background-color: #819e37; + border-color: #818b30; + color: #ffffff; } - .alert-danger, .alert-error { - color: #b94a48; - background-color: #f2dede; - border-color: #eed3d7; + background-color: #cd0200; + border-color: #be001e; + color: #ffffff; } - .alert-info { - color: #3a87ad; - background-color: #d9edf7; - border-color: #bce8f1; + background-color: #3399f3; + border-color: #11adf1; + color: #ffffff; } - .alert-block { padding-top: 14px; padding-bottom: 14px; } - .alert-block > p, .alert-block > ul { margin-bottom: 0; } - .alert-block p + p { margin-top: 5px; } - .nav { - margin-bottom: 20px; margin-left: 0; + margin-bottom: 21px; list-style: none; } - .nav > li > a { display: block; } - .nav > li > a:hover { text-decoration: none; background-color: #eeeeee; } - .nav > .pull-right { float: right; } - .nav-header { display: block; padding: 3px 15px; font-size: 11px; font-weight: bold; - line-height: 20px; - color: #999999; + line-height: 21px; + color: #bbbbbb; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); text-transform: uppercase; } - .nav li + .nav-header { margin-top: 9px; } - .nav-list { - padding-right: 15px; padding-left: 15px; + padding-right: 15px; margin-bottom: 0; } - .nav-list > li > a, .nav-list .nav-header { - margin-right: -15px; margin-left: -15px; + margin-right: -15px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); } - .nav-list > li > a { padding: 3px 15px; } - .nav-list > .active > a, .nav-list > .active > a:hover { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); - background-color: #0088cc; + background-color: #558bc4; } - .nav-list [class^="icon-"] { margin-right: 2px; } - .nav-list .divider { *width: 100%; height: 1px; - margin: 9px 1px; + margin: 9.5px 1px; *margin: -5px 0 5px; overflow: hidden; background-color: #e5e5e5; border-bottom: 1px solid #ffffff; } - .nav-tabs, .nav-pills { *zoom: 1; } - .nav-tabs:before, .nav-pills:before, .nav-tabs:after, .nav-pills:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .nav-tabs:after, .nav-pills:after { clear: both; } - .nav-tabs > li, .nav-pills > li { float: left; } - .nav-tabs > li > a, .nav-pills > li > a { padding-right: 12px; @@ -3852,155 +3231,128 @@ input[type="submit"].btn.btn-mini { margin-right: 2px; line-height: 14px; } - .nav-tabs { border-bottom: 1px solid #ddd; } - .nav-tabs > li { margin-bottom: -1px; } - .nav-tabs > li > a { padding-top: 8px; padding-bottom: 8px; - line-height: 20px; + line-height: 21px; border: 1px solid transparent; -webkit-border-radius: 4px 4px 0 0; - -moz-border-radius: 4px 4px 0 0; - border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; } - .nav-tabs > li > a:hover { border-color: #eeeeee #eeeeee #dddddd; } - .nav-tabs > .active > a, .nav-tabs > .active > a:hover { - color: #555555; - cursor: default; + color: #777777; background-color: #ffffff; border: 1px solid #ddd; border-bottom-color: transparent; + cursor: default; } - .nav-pills > li > a { padding-top: 8px; padding-bottom: 8px; margin-top: 2px; margin-bottom: 2px; -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; } - .nav-pills > .active > a, .nav-pills > .active > a:hover { color: #ffffff; - background-color: #0088cc; + background-color: #558bc4; } - .nav-stacked > li { float: none; } - .nav-stacked > li > a { margin-right: 0; } - .nav-tabs.nav-stacked { border-bottom: 0; } - .nav-tabs.nav-stacked > li > a { border: 1px solid #ddd; -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; } - .nav-tabs.nav-stacked > li:first-child > a { -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; - -webkit-border-top-left-radius: 4px; - border-top-left-radius: 4px; -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; } - .nav-tabs.nav-stacked > li:last-child > a { -webkit-border-bottom-right-radius: 4px; - border-bottom-right-radius: 4px; - -webkit-border-bottom-left-radius: 4px; - border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; } - .nav-tabs.nav-stacked > li > a:hover { - z-index: 2; border-color: #ddd; + z-index: 2; } - .nav-pills.nav-stacked > li > a { margin-bottom: 3px; } - .nav-pills.nav-stacked > li:last-child > a { margin-bottom: 1px; } - .nav-tabs .dropdown-menu { -webkit-border-radius: 0 0 6px 6px; - -moz-border-radius: 0 0 6px 6px; - border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; } - .nav-pills .dropdown-menu { -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; } - .nav .dropdown-toggle .caret { + border-top-color: #558bc4; + border-bottom-color: #558bc4; margin-top: 6px; - border-top-color: #0088cc; - border-bottom-color: #0088cc; } - .nav .dropdown-toggle:hover .caret { - border-top-color: #005580; - border-bottom-color: #005580; + border-top-color: #558bc4; + border-bottom-color: #558bc4; } - /* move down carets for tabs */ - .nav-tabs .dropdown-toggle .caret { margin-top: 8px; } - .nav .active .dropdown-toggle .caret { border-top-color: #fff; border-bottom-color: #fff; } - .nav-tabs .active .dropdown-toggle .caret { - border-top-color: #555555; - border-bottom-color: #555555; + border-top-color: #777777; + border-bottom-color: #777777; } - .nav > .dropdown.active > a:hover { cursor: pointer; } - .nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > li.dropdown.open.active > a:hover { color: #ffffff; - background-color: #999999; - border-color: #999999; + background-color: #bbbbbb; + border-color: #bbbbbb; } - .nav li.dropdown.open .caret, .nav li.dropdown.open.active .caret, .nav li.dropdown.open a:hover .caret { @@ -4009,312 +3361,260 @@ input[type="submit"].btn.btn-mini { opacity: 1; filter: alpha(opacity=100); } - .tabs-stacked .open > a:hover { - border-color: #999999; + border-color: #bbbbbb; } - .tabbable { *zoom: 1; } - .tabbable:before, .tabbable:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .tabbable:after { clear: both; } - .tab-content { overflow: auto; } - .tabs-below > .nav-tabs, .tabs-right > .nav-tabs, .tabs-left > .nav-tabs { border-bottom: 0; } - .tab-content > .tab-pane, .pill-content > .pill-pane { display: none; } - .tab-content > .active, .pill-content > .active { display: block; } - .tabs-below > .nav-tabs { border-top: 1px solid #ddd; } - .tabs-below > .nav-tabs > li { margin-top: -1px; margin-bottom: 0; } - .tabs-below > .nav-tabs > li > a { -webkit-border-radius: 0 0 4px 4px; - -moz-border-radius: 0 0 4px 4px; - border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; } - .tabs-below > .nav-tabs > li > a:hover { - border-top-color: #ddd; border-bottom-color: transparent; + border-top-color: #ddd; } - .tabs-below > .nav-tabs > .active > a, .tabs-below > .nav-tabs > .active > a:hover { border-color: transparent #ddd #ddd #ddd; } - .tabs-left > .nav-tabs > li, .tabs-right > .nav-tabs > li { float: none; } - .tabs-left > .nav-tabs > li > a, .tabs-right > .nav-tabs > li > a { min-width: 74px; margin-right: 0; margin-bottom: 3px; } - .tabs-left > .nav-tabs { float: left; margin-right: 19px; border-right: 1px solid #ddd; } - .tabs-left > .nav-tabs > li > a { margin-right: -1px; -webkit-border-radius: 4px 0 0 4px; - -moz-border-radius: 4px 0 0 4px; - border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; } - .tabs-left > .nav-tabs > li > a:hover { border-color: #eeeeee #dddddd #eeeeee #eeeeee; } - .tabs-left > .nav-tabs .active > a, .tabs-left > .nav-tabs .active > a:hover { border-color: #ddd transparent #ddd #ddd; *border-right-color: #ffffff; } - .tabs-right > .nav-tabs { float: right; margin-left: 19px; border-left: 1px solid #ddd; } - .tabs-right > .nav-tabs > li > a { margin-left: -1px; -webkit-border-radius: 0 4px 4px 0; - -moz-border-radius: 0 4px 4px 0; - border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; } - .tabs-right > .nav-tabs > li > a:hover { border-color: #eeeeee #eeeeee #eeeeee #dddddd; } - .tabs-right > .nav-tabs .active > a, .tabs-right > .nav-tabs .active > a:hover { border-color: #ddd #ddd #ddd transparent; *border-left-color: #ffffff; } - .nav > .disabled > a { - color: #999999; + color: #bbbbbb; } - .nav > .disabled > a:hover { text-decoration: none; - cursor: default; background-color: transparent; + cursor: default; } - .navbar { + overflow: visible; + margin-bottom: 21px; + color: #2d2d2d; *position: relative; *z-index: 2; - margin-bottom: 20px; - overflow: visible; - color: #777777; } - .navbar-inner { min-height: 40px; - padding-right: 20px; padding-left: 20px; - background-color: #fafafa; - background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2)); - background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); - background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); - background-image: linear-gradient(to bottom, #ffffff, #f2f2f2); + padding-right: 20px; + background-color: #dadada; + background-image: -moz-linear-gradient(top, #eeeeee, #bbbbbb); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#eeeeee), to(#bbbbbb)); + background-image: -webkit-linear-gradient(top, #eeeeee, #bbbbbb); + background-image: -o-linear-gradient(top, #eeeeee, #bbbbbb); + background-image: linear-gradient(to bottom, #eeeeee, #bbbbbb); background-repeat: repeat-x; - border: 1px solid #d4d4d4; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffeeeeee', endColorstr='#ffbbbbbb', GradientType=0); + border: 1px solid #aeaeae; -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); - *zoom: 1; + -moz-border-radius: 4px; + border-radius: 4px; -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); - -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + *zoom: 1; } - .navbar-inner:before, .navbar-inner:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .navbar-inner:after { clear: both; } - .navbar .container { width: auto; } - .nav-collapse.collapse { height: auto; } - .navbar .brand { - display: block; float: left; - padding: 10px 20px 10px; + display: block; + padding: 9.5px 20px 9.5px; margin-left: -20px; font-size: 20px; font-weight: 200; - color: #777777; - text-shadow: 0 1px 0 #ffffff; + color: #333333; + text-shadow: 0 1px 0 #eeeeee; } - .navbar .brand:hover { text-decoration: none; } - .navbar-text { margin-bottom: 0; line-height: 40px; } - .navbar-link { - color: #777777; + color: #2d2d2d; } - .navbar-link:hover { - color: #333333; + color: #558bc4; } - .navbar .divider-vertical { height: 40px; margin: 0 9px; - border-right: 1px solid #ffffff; - border-left: 1px solid #f2f2f2; + border-left: 1px solid #bbbbbb; + border-right: 1px solid #eeeeee; } - .navbar .btn, .navbar .btn-group { margin-top: 5px; } - .navbar .btn-group .btn, .navbar .input-prepend .btn, .navbar .input-append .btn { margin-top: 0; } - .navbar-form { margin-bottom: 0; *zoom: 1; } - .navbar-form:before, .navbar-form:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .navbar-form:after { clear: both; } - .navbar-form input, .navbar-form select, .navbar-form .radio, .navbar-form .checkbox { margin-top: 5px; } - .navbar-form input, .navbar-form select, .navbar-form .btn { display: inline-block; margin-bottom: 0; } - .navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { margin-top: 3px; } - .navbar-form .input-append, .navbar-form .input-prepend { margin-top: 6px; white-space: nowrap; } - .navbar-form .input-append input, .navbar-form .input-prepend input { margin-top: 0; } - .navbar-search { position: relative; float: left; margin-top: 5px; margin-bottom: 0; } - .navbar-search .search-query { - padding: 4px 14px; margin-bottom: 0; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + padding: 4px 14px; + font-family: "Muli", "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; font-weight: normal; line-height: 1; -webkit-border-radius: 15px; - -moz-border-radius: 15px; - border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; } - .navbar-static-top { position: static; width: 100%; margin-bottom: 0; } - .navbar-static-top .navbar-inner { -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; } - .navbar-fixed-top, .navbar-fixed-bottom { position: fixed; @@ -4323,52 +3623,43 @@ input[type="submit"].btn.btn-mini { z-index: 1030; margin-bottom: 0; } - .navbar-fixed-top .navbar-inner, .navbar-static-top .navbar-inner { border-width: 0 0 1px; } - .navbar-fixed-bottom .navbar-inner { border-width: 1px 0 0; } - .navbar-fixed-top .navbar-inner, .navbar-fixed-bottom .navbar-inner { - padding-right: 0; padding-left: 0; + padding-right: 0; -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; } - .navbar-static-top .container, .navbar-fixed-top .container, .navbar-fixed-bottom .container { width: 940px; } - .navbar-fixed-top { top: 0; } - .navbar-fixed-top .navbar-inner, .navbar-static-top .navbar-inner { -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); - -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); } - .navbar-fixed-bottom { bottom: 0; } - .navbar-fixed-bottom .navbar-inner { -webkit-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); - -moz-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); - box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); } - .navbar .nav { position: relative; left: 0; @@ -4376,286 +3667,249 @@ input[type="submit"].btn.btn-mini { float: left; margin: 0 10px 0 0; } - .navbar .nav.pull-right { float: right; margin-right: 0; } - .navbar .nav > li { float: left; } - .navbar .nav > li > a { float: none; - padding: 10px 15px 10px; - color: #777777; + padding: 9.5px 15px 9.5px; + color: #2d2d2d; text-decoration: none; - text-shadow: 0 1px 0 #ffffff; + text-shadow: 0 1px 0 #eeeeee; } - .navbar .nav .dropdown-toggle .caret { margin-top: 8px; } - .navbar .nav > li > a:focus, .navbar .nav > li > a:hover { - color: #333333; - text-decoration: none; background-color: transparent; + color: #558bc4; + text-decoration: none; } - .navbar .nav > .active > a, .navbar .nav > .active > a:hover, .navbar .nav > .active > a:focus { - color: #555555; + color: #2d2d2d; text-decoration: none; - background-color: #e5e5e5; + background-color: transparent; -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); - -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); - box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); } - .navbar .btn-navbar { display: none; float: right; padding: 7px 10px; - margin-right: 5px; margin-left: 5px; + margin-right: 5px; color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #ededed; - *background-color: #e5e5e5; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5)); - background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5); - background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5); - background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5); - background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5); + background-color: #cdcdcd; + background-image: -moz-linear-gradient(top, #e1e1e1, #aeaeae); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#e1e1e1), to(#aeaeae)); + background-image: -webkit-linear-gradient(top, #e1e1e1, #aeaeae); + background-image: -o-linear-gradient(top, #e1e1e1, #aeaeae); + background-image: linear-gradient(to bottom, #e1e1e1, #aeaeae); background-repeat: repeat-x; - border-color: #e5e5e5 #e5e5e5 #bfbfbf; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe1e1e1', endColorstr='#ffaeaeae', GradientType=0); + border-color: #aeaeae #aeaeae #888888; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); - -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); -} + *background-color: #aeaeae; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} .navbar .btn-navbar:hover, .navbar .btn-navbar:active, .navbar .btn-navbar.active, .navbar .btn-navbar.disabled, .navbar .btn-navbar[disabled] { color: #ffffff; - background-color: #e5e5e5; - *background-color: #d9d9d9; + background-color: #aeaeae; + *background-color: #a1a1a1; } - .navbar .btn-navbar:active, .navbar .btn-navbar.active { - background-color: #cccccc \9; + background-color: #959595 \9; } - .navbar .btn-navbar .icon-bar { display: block; width: 18px; height: 2px; background-color: #f5f5f5; -webkit-border-radius: 1px; - -moz-border-radius: 1px; - border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); - -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); - box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); } - .btn-navbar .icon-bar + .icon-bar { margin-top: 3px; } - .navbar .nav > li > .dropdown-menu:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); position: absolute; top: -7px; left: 9px; - display: inline-block; - border-right: 7px solid transparent; - border-bottom: 7px solid #ccc; - border-left: 7px solid transparent; - border-bottom-color: rgba(0, 0, 0, 0.2); - content: ''; } - .navbar .nav > li > .dropdown-menu:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; position: absolute; top: -6px; left: 10px; - display: inline-block; - border-right: 6px solid transparent; - border-bottom: 6px solid #ffffff; - border-left: 6px solid transparent; - content: ''; } - .navbar-fixed-bottom .nav > li > .dropdown-menu:before { - top: auto; - bottom: -7px; border-top: 7px solid #ccc; - border-bottom: 0; border-top-color: rgba(0, 0, 0, 0.2); -} - -.navbar-fixed-bottom .nav > li > .dropdown-menu:after { + border-bottom: 0; + bottom: -7px; top: auto; - bottom: -6px; +} +.navbar-fixed-bottom .nav > li > .dropdown-menu:after { border-top: 6px solid #ffffff; border-bottom: 0; + bottom: -6px; + top: auto; } - .navbar .nav li.dropdown.open > .dropdown-toggle, .navbar .nav li.dropdown.active > .dropdown-toggle, .navbar .nav li.dropdown.open.active > .dropdown-toggle { - color: #555555; - background-color: #e5e5e5; + background-color: transparent; + color: #2d2d2d; } - .navbar .nav li.dropdown > .dropdown-toggle .caret { - border-top-color: #777777; - border-bottom-color: #777777; + border-top-color: #2d2d2d; + border-bottom-color: #2d2d2d; } - .navbar .nav li.dropdown.open > .dropdown-toggle .caret, .navbar .nav li.dropdown.active > .dropdown-toggle .caret, .navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { - border-top-color: #555555; - border-bottom-color: #555555; + border-top-color: #2d2d2d; + border-bottom-color: #2d2d2d; } - .navbar .pull-right > li > .dropdown-menu, .navbar .nav > li > .dropdown-menu.pull-right { - right: 0; left: auto; + right: 0; } - .navbar .pull-right > li > .dropdown-menu:before, .navbar .nav > li > .dropdown-menu.pull-right:before { - right: 12px; left: auto; + right: 12px; } - .navbar .pull-right > li > .dropdown-menu:after, .navbar .nav > li > .dropdown-menu.pull-right:after { - right: 13px; left: auto; + right: 13px; } - .navbar .pull-right > li > .dropdown-menu .dropdown-menu, .navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu { - right: 100%; left: auto; - margin-right: -1px; + right: 100%; margin-left: 0; + margin-right: -1px; -webkit-border-radius: 6px 0 6px 6px; - -moz-border-radius: 6px 0 6px 6px; - border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; } - .navbar-inverse { - color: #999999; + color: #eeeeee; } - .navbar-inverse .navbar-inner { - background-color: #1b1b1b; - background-image: -moz-linear-gradient(top, #222222, #111111); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111)); - background-image: -webkit-linear-gradient(top, #222222, #111111); - background-image: -o-linear-gradient(top, #222222, #111111); - background-image: linear-gradient(to bottom, #222222, #111111); + background-color: #949aa2; + background-image: -moz-linear-gradient(top, #afb3ba, #6c737e); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#afb3ba), to(#6c737e)); + background-image: -webkit-linear-gradient(top, #afb3ba, #6c737e); + background-image: -o-linear-gradient(top, #afb3ba, #6c737e); + background-image: linear-gradient(to bottom, #afb3ba, #6c737e); background-repeat: repeat-x; - border-color: #252525; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffafb3ba', endColorstr='#ff6c737e', GradientType=0); + border-color: #606670; } - .navbar-inverse .brand, .navbar-inverse .nav > li > a { - color: #999999; + color: #eeeeee; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } - .navbar-inverse .brand:hover, .navbar-inverse .nav > li > a:hover { color: #ffffff; } - .navbar-inverse .nav > li > a:focus, .navbar-inverse .nav > li > a:hover { - color: #ffffff; background-color: transparent; + color: #ffffff; } - .navbar-inverse .nav .active > a, .navbar-inverse .nav .active > a:hover, .navbar-inverse .nav .active > a:focus { color: #ffffff; - background-color: #111111; + background-color: #6c737e; } - .navbar-inverse .navbar-link { - color: #999999; + color: #eeeeee; } - .navbar-inverse .navbar-link:hover { color: #ffffff; } - .navbar-inverse .divider-vertical { - border-right-color: #222222; - border-left-color: #111111; + border-left-color: #6c737e; + border-right-color: #afb3ba; } - .navbar-inverse .nav li.dropdown.open > .dropdown-toggle, .navbar-inverse .nav li.dropdown.active > .dropdown-toggle, .navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { + background-color: #6c737e; color: #ffffff; - background-color: #111111; } - .navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { - border-top-color: #999999; - border-bottom-color: #999999; + border-top-color: #eeeeee; + border-bottom-color: #eeeeee; } - .navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret, .navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret, .navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; } - .navbar-inverse .navbar-search .search-query { color: #ffffff; - background-color: #515151; - border-color: #111111; + background-color: #afb3ba; + border-color: #6c737e; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); - -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); -webkit-transition: none; - -moz-transition: none; - -o-transition: none; - transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; } - .navbar-inverse .navbar-search .search-query:-moz-placeholder { - color: #cccccc; + color: #eeeeee; } - .navbar-inverse .navbar-search .search-query:-ms-input-placeholder { - color: #cccccc; + color: #eeeeee; } - .navbar-inverse .navbar-search .search-query::-webkit-input-placeholder { - color: #cccccc; + color: #eeeeee; } - .navbar-inverse .navbar-search .search-query:focus, .navbar-inverse .navbar-search .search-query.focused { padding: 5px 15px; @@ -4663,169 +3917,152 @@ input[type="submit"].btn.btn-mini { text-shadow: 0 1px 0 #ffffff; background-color: #ffffff; border: 0; - outline: 0; -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); - -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); - box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + outline: 0; } - .navbar-inverse .btn-navbar { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #0e0e0e; - *background-color: #040404; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404)); - background-image: -webkit-linear-gradient(top, #151515, #040404); - background-image: -o-linear-gradient(top, #151515, #040404); - background-image: linear-gradient(to bottom, #151515, #040404); - background-image: -moz-linear-gradient(top, #151515, #040404); + background-color: #878d96; + background-image: -moz-linear-gradient(top, #a1a7af, #606670); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#a1a7af), to(#606670)); + background-image: -webkit-linear-gradient(top, #a1a7af, #606670); + background-image: -o-linear-gradient(top, #a1a7af, #606670); + background-image: linear-gradient(to bottom, #a1a7af, #606670); background-repeat: repeat-x; - border-color: #040404 #040404 #000000; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa1a7af', endColorstr='#ff606670', GradientType=0); + border-color: #606670 #606670 #3d4147; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); -} + *background-color: #606670; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} .navbar-inverse .btn-navbar:hover, .navbar-inverse .btn-navbar:active, .navbar-inverse .btn-navbar.active, .navbar-inverse .btn-navbar.disabled, .navbar-inverse .btn-navbar[disabled] { color: #ffffff; - background-color: #040404; - *background-color: #000000; + background-color: #606670; + *background-color: #545a63; } - .navbar-inverse .btn-navbar:active, .navbar-inverse .btn-navbar.active { - background-color: #000000 \9; + background-color: #494d55 \9; } - .breadcrumb { padding: 8px 15px; - margin: 0 0 20px; + margin: 0 0 21px; list-style: none; background-color: #f5f5f5; -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; } - .breadcrumb li { display: inline-block; *display: inline; - text-shadow: 0 1px 0 #ffffff; - *zoom: 1; -} + /* IE7 inline-block hack */ + *zoom: 1; + text-shadow: 0 1px 0 #ffffff; +} .breadcrumb .divider { padding: 0 5px; color: #ccc; } - .breadcrumb .active { - color: #999999; + color: #bbbbbb; } - .pagination { - height: 40px; - margin: 20px 0; + height: 42px; + margin: 21px 0; } - .pagination ul { display: inline-block; *display: inline; - margin-bottom: 0; - margin-left: 0; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - *zoom: 1; - -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); -} + /* IE7 inline-block hack */ + *zoom: 1; + margin-left: 0; + margin-bottom: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} .pagination ul > li { display: inline; } - .pagination ul > li > a, .pagination ul > li > span { float: left; padding: 0 14px; - line-height: 38px; + line-height: 40px; text-decoration: none; background-color: #ffffff; border: 1px solid #dddddd; border-left-width: 0; } - .pagination ul > li > a:hover, .pagination ul > .active > a, .pagination ul > .active > span { background-color: #f5f5f5; } - .pagination ul > .active > a, .pagination ul > .active > span { - color: #999999; + color: #bbbbbb; cursor: default; } - .pagination ul > .disabled > span, .pagination ul > .disabled > a, .pagination ul > .disabled > a:hover { - color: #999999; - cursor: default; + color: #bbbbbb; background-color: transparent; + cursor: default; } - .pagination ul > li:first-child > a, .pagination ul > li:first-child > span { border-left-width: 1px; -webkit-border-radius: 3px 0 0 3px; - -moz-border-radius: 3px 0 0 3px; - border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; } - .pagination ul > li:last-child > a, .pagination ul > li:last-child > span { -webkit-border-radius: 0 3px 3px 0; - -moz-border-radius: 0 3px 3px 0; - border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; } - .pagination-centered { text-align: center; } - .pagination-right { text-align: right; } - .pager { - margin: 20px 0; - text-align: center; + margin: 21px 0; list-style: none; + text-align: center; *zoom: 1; } - .pager:before, .pager:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .pager:after { clear: both; } - .pager li { display: inline; } - .pager a, .pager span { display: inline-block; @@ -4833,48 +4070,39 @@ input[type="submit"].btn.btn-mini { background-color: #fff; border: 1px solid #ddd; -webkit-border-radius: 15px; - -moz-border-radius: 15px; - border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; } - .pager a:hover { text-decoration: none; background-color: #f5f5f5; } - .pager .next a, .pager .next span { float: right; } - .pager .previous a { float: left; } - .pager .disabled a, .pager .disabled a:hover, .pager .disabled span { - color: #999999; - cursor: default; + color: #bbbbbb; background-color: #fff; + cursor: default; } - .modal-open .modal .dropdown-menu { z-index: 2050; } - .modal-open .modal .dropdown.open { *z-index: 2050; } - .modal-open .modal .popover { z-index: 2060; } - .modal-open .modal .tooltip { z-index: 2080; } - .modal-backdrop { position: fixed; top: 0; @@ -4884,76 +4112,67 @@ input[type="submit"].btn.btn-mini { z-index: 1040; background-color: #000000; } - .modal-backdrop.fade { opacity: 0; } - .modal-backdrop, .modal-backdrop.fade.in { opacity: 0.8; filter: alpha(opacity=80); } - .modal { position: fixed; top: 50%; left: 50%; z-index: 1050; + overflow: auto; width: 560px; margin: -250px 0 0 -280px; - overflow: auto; background-color: #ffffff; border: 1px solid #999; border: 1px solid rgba(0, 0, 0, 0.3); *border: 1px solid #999; + /* IE6-7 */ + -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); - -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); - box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); -webkit-background-clip: padding-box; - -moz-background-clip: padding-box; - background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; } - .modal.fade { + -webkit-transition: opacity .3s linear, top .3s ease-out; + -moz-transition: opacity .3s linear, top .3s ease-out; + -o-transition: opacity .3s linear, top .3s ease-out; + transition: opacity .3s linear, top .3s ease-out; top: -25%; - -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; - -moz-transition: opacity 0.3s linear, top 0.3s ease-out; - -o-transition: opacity 0.3s linear, top 0.3s ease-out; - transition: opacity 0.3s linear, top 0.3s ease-out; } - .modal.fade.in { top: 50%; } - .modal-header { padding: 9px 15px; border-bottom: 1px solid #eee; } - .modal-header .close { margin-top: 2px; } - .modal-header h3 { margin: 0; line-height: 30px; } - .modal-body { + overflow-y: auto; max-height: 400px; padding: 15px; - overflow-y: auto; } - .modal-form { margin-bottom: 0; } - .modal-footer { padding: 14px 15px 15px; margin-bottom: 0; @@ -4961,66 +4180,55 @@ input[type="submit"].btn.btn-mini { background-color: #f5f5f5; border-top: 1px solid #ddd; -webkit-border-radius: 0 0 6px 6px; - -moz-border-radius: 0 0 6px 6px; - border-radius: 0 0 6px 6px; - *zoom: 1; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; -webkit-box-shadow: inset 0 1px 0 #ffffff; - -moz-box-shadow: inset 0 1px 0 #ffffff; - box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; + *zoom: 1; } - .modal-footer:before, .modal-footer:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .modal-footer:after { clear: both; } - .modal-footer .btn + .btn { - margin-bottom: 0; margin-left: 5px; + margin-bottom: 0; } - .modal-footer .btn-group .btn + .btn { margin-left: -1px; } - .tooltip { position: absolute; z-index: 1030; display: block; + visibility: visible; padding: 5px; font-size: 11px; opacity: 0; filter: alpha(opacity=0); - visibility: visible; } - .tooltip.in { opacity: 0.8; filter: alpha(opacity=80); } - .tooltip.top { margin-top: -3px; } - .tooltip.right { margin-left: 3px; } - .tooltip.bottom { margin-top: 3px; } - .tooltip.left { margin-left: -3px; } - .tooltip-inner { max-width: 200px; padding: 3px 8px; @@ -5029,10 +4237,9 @@ input[type="submit"].btn.btn-mini { text-decoration: none; background-color: #000000; -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; } - .tooltip-arrow { position: absolute; width: 0; @@ -5040,39 +4247,34 @@ input[type="submit"].btn.btn-mini { border-color: transparent; border-style: solid; } - .tooltip.top .tooltip-arrow { bottom: 0; left: 50%; margin-left: -5px; - border-top-color: #000000; border-width: 5px 5px 0; + border-top-color: #000000; } - .tooltip.right .tooltip-arrow { top: 50%; left: 0; margin-top: -5px; - border-right-color: #000000; border-width: 5px 5px 5px 0; + border-right-color: #000000; } - .tooltip.left .tooltip-arrow { top: 50%; right: 0; margin-top: -5px; - border-left-color: #000000; border-width: 5px 0 5px 5px; + border-left-color: #000000; } - .tooltip.bottom .tooltip-arrow { top: 0; left: 50%; margin-left: -5px; - border-bottom-color: #000000; border-width: 0 5px 5px; + border-bottom-color: #000000; } - .popover { position: absolute; top: 0; @@ -5082,58 +4284,50 @@ input[type="submit"].btn.btn-mini { width: 236px; padding: 1px; background-color: #ffffff; + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.2); -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - -webkit-background-clip: padding-box; - -moz-background-clip: padding; - background-clip: padding-box; + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); } - .popover.top { margin-bottom: 10px; } - .popover.right { margin-left: 10px; } - .popover.bottom { margin-top: 10px; } - .popover.left { margin-right: 10px; } - .popover-title { - padding: 8px 14px; margin: 0; + padding: 8px 14px; font-size: 14px; font-weight: normal; line-height: 18px; background-color: #f7f7f7; border-bottom: 1px solid #ebebeb; -webkit-border-radius: 5px 5px 0 0; - -moz-border-radius: 5px 5px 0 0; - border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; } - .popover-content { padding: 9px 14px; } - .popover-content p, .popover-content ul, .popover-content ol { margin-bottom: 0; } - .popover .arrow, .popover .arrow:after { position: absolute; @@ -5143,229 +4337,194 @@ input[type="submit"].btn.btn-mini { border-color: transparent; border-style: solid; } - .popover .arrow:after { - z-index: -1; content: ""; + z-index: -1; } - .popover.top .arrow { bottom: -10px; left: 50%; margin-left: -10px; - border-top-color: #ffffff; border-width: 10px 10px 0; + border-top-color: #ffffff; } - .popover.top .arrow:after { + border-width: 11px 11px 0; + border-top-color: rgba(0, 0, 0, 0.25); bottom: -1px; left: -11px; - border-top-color: rgba(0, 0, 0, 0.25); - border-width: 11px 11px 0; } - .popover.right .arrow { top: 50%; left: -10px; margin-top: -10px; - border-right-color: #ffffff; border-width: 10px 10px 10px 0; + border-right-color: #ffffff; } - .popover.right .arrow:after { + border-width: 11px 11px 11px 0; + border-right-color: rgba(0, 0, 0, 0.25); bottom: -11px; left: -1px; - border-right-color: rgba(0, 0, 0, 0.25); - border-width: 11px 11px 11px 0; } - .popover.bottom .arrow { top: -10px; left: 50%; margin-left: -10px; - border-bottom-color: #ffffff; border-width: 0 10px 10px; + border-bottom-color: #ffffff; } - .popover.bottom .arrow:after { + border-width: 0 11px 11px; + border-bottom-color: rgba(0, 0, 0, 0.25); top: -1px; left: -11px; - border-bottom-color: rgba(0, 0, 0, 0.25); - border-width: 0 11px 11px; } - .popover.left .arrow { top: 50%; right: -10px; margin-top: -10px; - border-left-color: #ffffff; border-width: 10px 0 10px 10px; + border-left-color: #ffffff; } - .popover.left .arrow:after { - right: -1px; - bottom: -11px; - border-left-color: rgba(0, 0, 0, 0.25); border-width: 11px 0 11px 11px; + border-left-color: rgba(0, 0, 0, 0.25); + bottom: -11px; + right: -1px; } - .thumbnails { margin-left: -20px; list-style: none; *zoom: 1; } - .thumbnails:before, .thumbnails:after { display: table; - line-height: 0; content: ""; + line-height: 0; } - .thumbnails:after { clear: both; } - .row-fluid .thumbnails { margin-left: 0; } - .thumbnails > li { float: left; - margin-bottom: 20px; + margin-bottom: 21px; margin-left: 20px; } - .thumbnail { display: block; padding: 4px; - line-height: 20px; + line-height: 21px; border: 1px solid #ddd; -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); - -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); -webkit-transition: all 0.2s ease-in-out; - -moz-transition: all 0.2s ease-in-out; - -o-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; } - a.thumbnail:hover { - border-color: #0088cc; + border-color: #558bc4; -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); - -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); - box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); } - .thumbnail > img { display: block; max-width: 100%; - margin-right: auto; margin-left: auto; + margin-right: auto; } - .thumbnail .caption { padding: 9px; - color: #555555; + color: #777777; } - .label, .badge { font-size: 11.844px; font-weight: bold; line-height: 14px; color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - white-space: nowrap; vertical-align: baseline; - background-color: #999999; + white-space: nowrap; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #bbbbbb; } - .label { padding: 1px 4px 2px; -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } - .badge { padding: 1px 9px 2px; -webkit-border-radius: 9px; - -moz-border-radius: 9px; - border-radius: 9px; + -moz-border-radius: 9px; + border-radius: 9px; } - a.label:hover, a.badge:hover { color: #ffffff; text-decoration: none; cursor: pointer; } - .label-important, .badge-important { - background-color: #b94a48; + background-color: #ffffff; } - .label-important[href], .badge-important[href] { - background-color: #953b39; + background-color: #e6e6e6; } - .label-warning, .badge-warning { - background-color: #f89406; + background-color: #d47500; } - .label-warning[href], .badge-warning[href] { - background-color: #c67605; + background-color: #a15900; } - .label-success, .badge-success { - background-color: #468847; + background-color: #ffffff; } - .label-success[href], .badge-success[href] { - background-color: #356635; + background-color: #e6e6e6; } - .label-info, .badge-info { - background-color: #3a87ad; + background-color: #ffffff; } - .label-info[href], .badge-info[href] { - background-color: #2d6987; + background-color: #e6e6e6; } - .label-inverse, .badge-inverse { background-color: #333333; } - .label-inverse[href], .badge-inverse[href] { background-color: #1a1a1a; } - .btn .label, .btn .badge { position: relative; top: -1px; } - .btn-mini .label, .btn-mini .badge { top: 0; } - @-webkit-keyframes progress-bar-stripes { from { background-position: 40px 0; @@ -5374,7 +4533,6 @@ a.badge:hover { background-position: 0 0; } } - @-moz-keyframes progress-bar-stripes { from { background-position: 40px 0; @@ -5383,7 +4541,6 @@ a.badge:hover { background-position: 0 0; } } - @-ms-keyframes progress-bar-stripes { from { background-position: 40px 0; @@ -5392,7 +4549,6 @@ a.badge:hover { background-position: 0 0; } } - @-o-keyframes progress-bar-stripes { from { background-position: 0 0; @@ -5401,7 +4557,6 @@ a.badge:hover { background-position: 40px 0; } } - @keyframes progress-bar-stripes { from { background-position: 40px 0; @@ -5410,11 +4565,10 @@ a.badge:hover { background-position: 0 0; } } - .progress { - height: 20px; - margin-bottom: 20px; overflow: hidden; + height: 21px; + margin-bottom: 21px; background-color: #f7f7f7; background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); @@ -5422,21 +4576,20 @@ a.badge:hover { background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); background-repeat: repeat-x; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); - -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; } - .progress .bar { - float: left; - width: 0; + width: 0%; height: 100%; - font-size: 12px; color: #ffffff; + float: left; + font-size: 12px; text-align: center; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #0e90d2; @@ -5446,25 +4599,23 @@ a.badge:hover { background-image: -o-linear-gradient(top, #149bdf, #0480be); background-image: linear-gradient(to bottom, #149bdf, #0480be); background-repeat: repeat-x; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; -webkit-transition: width 0.6s ease; - -moz-transition: width 0.6s ease; - -o-transition: width 0.6s ease; - transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; } - .progress .bar + .bar { -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); - -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); - box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); } - .progress-striped .bar { background-color: #149bdf; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); @@ -5473,19 +4624,17 @@ a.badge:hover { background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -webkit-background-size: 40px 40px; - -moz-background-size: 40px 40px; - -o-background-size: 40px 40px; - background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; } - .progress.active .bar { -webkit-animation: progress-bar-stripes 2s linear infinite; - -moz-animation: progress-bar-stripes 2s linear infinite; - -ms-animation: progress-bar-stripes 2s linear infinite; - -o-animation: progress-bar-stripes 2s linear infinite; - animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; } - .progress-danger .bar, .progress .bar-danger { background-color: #dd514c; @@ -5495,9 +4644,8 @@ a.badge:hover { background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); background-image: linear-gradient(to bottom, #ee5f5b, #c43c35); background-repeat: repeat-x; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); } - .progress-danger.progress-striped .bar, .progress-striped .bar-danger { background-color: #ee5f5b; @@ -5507,7 +4655,6 @@ a.badge:hover { background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } - .progress-success .bar, .progress .bar-success { background-color: #5eb95e; @@ -5517,9 +4664,8 @@ a.badge:hover { background-image: -o-linear-gradient(top, #62c462, #57a957); background-image: linear-gradient(to bottom, #62c462, #57a957); background-repeat: repeat-x; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); } - .progress-success.progress-striped .bar, .progress-striped .bar-success { background-color: #62c462; @@ -5529,7 +4675,6 @@ a.badge:hover { background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } - .progress-info .bar, .progress .bar-info { background-color: #4bb1cf; @@ -5539,9 +4684,8 @@ a.badge:hover { background-image: -o-linear-gradient(top, #5bc0de, #339bb9); background-image: linear-gradient(to bottom, #5bc0de, #339bb9); background-repeat: repeat-x; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); } - .progress-info.progress-striped .bar, .progress-striped .bar-info { background-color: #5bc0de; @@ -5551,123 +4695,102 @@ a.badge:hover { background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } - .progress-warning .bar, .progress .bar-warning { - background-color: #faa732; - background-image: -moz-linear-gradient(top, #fbb450, #f89406); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); - background-image: -webkit-linear-gradient(top, #fbb450, #f89406); - background-image: -o-linear-gradient(top, #fbb450, #f89406); - background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-color: #ee8c14; + background-image: -moz-linear-gradient(top, #ff9c21, #d47500); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ff9c21), to(#d47500)); + background-image: -webkit-linear-gradient(top, #ff9c21, #d47500); + background-image: -o-linear-gradient(top, #ff9c21, #d47500); + background-image: linear-gradient(to bottom, #ff9c21, #d47500); background-repeat: repeat-x; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff9c21', endColorstr='#ffd47500', GradientType=0); } - .progress-warning.progress-striped .bar, .progress-striped .bar-warning { - background-color: #fbb450; + background-color: #ff9c21; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } - .accordion { - margin-bottom: 20px; + margin-bottom: 21px; } - .accordion-group { margin-bottom: 2px; border: 1px solid #e5e5e5; -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; } - .accordion-heading { border-bottom: 0; } - .accordion-heading .accordion-toggle { display: block; padding: 8px 15px; } - .accordion-toggle { cursor: pointer; } - .accordion-inner { padding: 9px 15px; border-top: 1px solid #e5e5e5; } - .carousel { position: relative; - margin-bottom: 20px; + margin-bottom: 21px; line-height: 1; } - .carousel-inner { - position: relative; - width: 100%; overflow: hidden; -} - -.carousel .item { + width: 100%; position: relative; - display: none; - -webkit-transition: 0.6s ease-in-out left; - -moz-transition: 0.6s ease-in-out left; - -o-transition: 0.6s ease-in-out left; - transition: 0.6s ease-in-out left; } - +.carousel .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} .carousel .item > img { display: block; line-height: 1; } - .carousel .active, .carousel .next, .carousel .prev { display: block; } - .carousel .active { left: 0; } - .carousel .next, .carousel .prev { position: absolute; top: 0; width: 100%; } - .carousel .next { left: 100%; } - .carousel .prev { left: -100%; } - .carousel .next.left, .carousel .prev.right { left: 0; } - .carousel .active.left { left: -100%; } - .carousel .active.right { left: 100%; } - .carousel-control { position: absolute; top: 40%; @@ -5680,95 +4803,422 @@ a.badge:hover { line-height: 30px; color: #ffffff; text-align: center; - background: #222222; + background: #2d2d2d; border: 3px solid #ffffff; -webkit-border-radius: 23px; - -moz-border-radius: 23px; - border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; opacity: 0.5; filter: alpha(opacity=50); } - .carousel-control.right { - right: 15px; left: auto; + right: 15px; } - .carousel-control:hover { color: #ffffff; text-decoration: none; opacity: 0.9; filter: alpha(opacity=90); } - .carousel-caption { position: absolute; + left: 0; right: 0; bottom: 0; - left: 0; padding: 15px; background: #333333; background: rgba(0, 0, 0, 0.75); } - .carousel-caption h4, .carousel-caption p { - line-height: 20px; color: #ffffff; + line-height: 21px; } - .carousel-caption h4 { margin: 0 0 5px; } - .carousel-caption p { margin-bottom: 0; } - .hero-unit { padding: 60px; margin-bottom: 30px; background-color: #eeeeee; -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; } - .hero-unit h1 { margin-bottom: 0; font-size: 60px; line-height: 1; - letter-spacing: -1px; color: inherit; + letter-spacing: -1px; } - .hero-unit p { font-size: 18px; font-weight: 200; - line-height: 30px; + line-height: 31.5px; color: inherit; } - .pull-right { float: right; } - .pull-left { float: left; } - .hide { display: none; } - .show { display: block; } - .invisible { visibility: hidden; } +.affix { + position: fixed; +} +.navbar .navbar-inner { + border-bottom: 1px solid #CACACA; + -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.4) , 0 0 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.4) , 0 0 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 0 rgba(255, 255, 255, 0.4) , 0 0 10px rgba(0, 0, 0, 0.1); +} +.navbar .brand { + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3); +} +.navbar .brand:hover { + color: #558bc4; +} +.navbar .nav > li > a { + padding: 11px 10px 9px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3); +} +.navbar .navbar-text { + margin-top: 2px; + padding: 0 10px; + line-height: 38px; +} +.navbar .navbar-search .search-query, +.navbar .navbar-search .search-query:hover { + margin-bottom: 0; + line-height: normal; + color: #bbbbbb; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5); +} +.navbar .navbar-search .search-query:-moz-placeholder, +.navbar .navbar-search .search-query:hover:-moz-placeholder { + color: #bbbbbb; +} +.navbar .navbar-search .search-query:-ms-input-placeholder, +.navbar .navbar-search .search-query:hover:-ms-input-placeholder { + color: #bbbbbb; +} +.navbar .navbar-search .search-query::-webkit-input-placeholder, +.navbar .navbar-search .search-query:hover::-webkit-input-placeholder { + color: #bbbbbb; +} +.navbar .navbar-search .search-query:focus, +.navbar .navbar-search .search-query:hover:focus, +.navbar .navbar-search .search-query.focused, +.navbar .navbar-search .search-query:hover.focused { + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5); + color: #2d2d2d; +} +.navbar-inverse .brand { + text-shadow: -1px -1px 0 rgba(0, 0, 0, 0.3); +} +.navbar-inverse .brand:hover { + color: #ffffff; +} +.navbar-inverse .nav > li > a { + text-shadow: -1px -1px 0 rgba(0, 0, 0, 0.3); +} +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown:hover > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.open:hover > .dropdown-toggle .caret { + border-top-color: #ffffff; +} +.navbar-inverse .navbar-search .search-query, +.navbar-inverse .navbar-search .search-query:hover { + color: #ffffff; +} +.navbar-inverse .navbar-search .search-query:-moz-placeholder, +.navbar-inverse .navbar-search .search-query:hover:-moz-placeholder { + color: #eeeeee; +} +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder, +.navbar-inverse .navbar-search .search-query:hover:-ms-input-placeholder { + color: #eeeeee; +} +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder, +.navbar-inverse .navbar-search .search-query:hover::-webkit-input-placeholder { + color: #eeeeee; +} +@media (max-width: 979px) { + .navbar .nav-collapse .nav li > a:hover { + background-color: #558bc4; + color: #ffffff; + text-shadow: none; + } + .navbar .nav-collapse .navbar-search { + border-top: none; + border-bottom: none; + } + .navbar-inverse .nav-collapse .nav li > a { + color: #eeeeee; + } + .navbar-inverse .nav-collapse .nav li > a:hover { + background-color: #558bc4 !important; + } + .navbar-inverse .nav-collapse .nav-header { + color: #eeeeee; + } +} +div.subnav .nav > li > a { + color: #2d2d2d; +} +div.subnav .nav > li > a:hover { + color: #558bc4; +} +div.subnav .nav > li.active > a { + color: #2d2d2d; +} +div.subnav .nav > li.active > a:hover { + color: #2d2d2d; +} +div.subnav .nav > li.dropdown > .dropdown-toggle { + background-color: transparent; +} +div.subnav .nav > li.dropdown.open > .dropdown-toggle { + border-left: 1px solid whiteSmoke; + border-right: 1px solid #E5E5E5; + color: #2d2d2d; +} +div.subnav .nav > li.dropdown.open > .dropdown-toggle:hover { + color: #558bc4; +} +.nav > li.dropdown > .dropdown-toggle .caret, +.nav > li.dropdown.active > .dropdown-toggle .caret, +.nav > li.dropdown.open > .dropdown-toggle .caret, +.nav > li.dropdown.open.active > .dropdown-toggle .caret { + border-top: 4px solid #2d2d2d; + border-top-color: #2d2d2d; + opacity: 1; +} +.nav > li.dropdown > .dropdown-toggle:hover .caret, +.nav > li.dropdown.active > .dropdown-toggle:hover .caret, +.nav > li.dropdown.open > .dropdown-toggle:hover .caret, +.nav > li.dropdown.open.active > .dropdown-toggle:hover .caret { + border-top: 4px solid #558bc4; + border-top-color: #558bc4; +} +.btn-info, +.btn-info:hover, +.btn-info.disabled { + color: #2d2d2d; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3); +} +.btn-info .caret, +.btn-info:hover .caret, +.btn-info.disabled .caret { + border-top-color: #2d2d2d; + border-bottom-color: #2d2d2d; +} +/*.btn { + .buttonBackground(#F4F4F4, #ECECEC); + color: @textColor; + text-shadow: none; + + &:hover, + &:active, + &.active, + &.disabled, + &[disabled] { + color: @grayDark; + } +} + +.btn-primary { + .buttonBackground(#909090, #3F3F3F); +} + +.btn-warning { + .buttonBackground(lighten(@yellow, 15%), @yellow); +} + +.btn-danger { + .buttonBackground(lighten(#DA2D2D, 15%), #DA2D2D); +} + +.btn-success { + .buttonBackground(#8ADD6D, #60B044); +} + +.btn-info { + .buttonBackground(lighten(#4488BB, 15%), #4488BB); +} + +.btn-inverse { + .buttonBackground(lighten(@purple, 5%), @purple); +}*/ +.control-group.warning > label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #e29235; +} +.control-group.warning .checkbox, +.control-group.warning .radio, +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #e29235; +} +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + border-color: #e29235; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #c7781d; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #efc28e; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #efc28e; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #efc28e; +} +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #e29235; + background-color: #d47500; + border-color: #e29235; +} +.control-group.error > label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #cc0000; +} +.control-group.error .checkbox, +.control-group.error .radio, +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #cc0000; +} +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + border-color: #cc0000; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #990000; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ff3333; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ff3333; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ff3333; +} +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #cc0000; + background-color: #cd0200; + border-color: #cc0000; +} +.control-group.success > label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #2ba949; +} +.control-group.success .checkbox, +.control-group.success .radio, +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #2ba949; +} +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + border-color: #2ba949; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #218037; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #63d77e; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #63d77e; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #63d77e; +} +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #2ba949; + background-color: #819e37; + border-color: #2ba949; +} +.alert { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.label, +.badge { + padding-top: 4px; +} +.label-important, +.badge-important { + background-color: #cd0200; +} +.label-warning, +.badge-warning { + background-color: #d47500; +} +.label-success, +.badge-success { + background-color: #819e37; +} +.label-info, +.badge-info { + background-color: #3399f3; +} +.well { + background-color: #eeeeee; +} +.hero-unit { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + border: 1px solid rgba(0, 0, 0, 0.05); +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} .affix { position: fixed; } diff --git a/docs/public/css/base.scss b/docs/public/css/base.scss index eafd7d02..260f8309 100644 --- a/docs/public/css/base.scss +++ b/docs/public/css/base.scss @@ -85,4 +85,8 @@ section { h3 code { border: 0; font-size: 20px; +} + +footer { + text-align: center; } \ No newline at end of file diff --git a/docs/site.yml b/docs/site.yml index 4c752db0..b0d760ef 100644 --- a/docs/site.yml +++ b/docs/site.yml @@ -5,7 +5,9 @@ jq_version: 1.0 footer: | This website is made with [Bonsai](http://www.tinytree.info) and - [Twitter Boostrap](http://twitter.github.com/bootstrap/). jq is - licensed under the MIT license (code) and the + [Twitter Boostrap](http://twitter.github.com/bootstrap/), themed + with [Bootswatch](http://bootswatch.com). + + jq is licensed under the MIT license (code) and the [CC-BY-3.0](http://creativecommons.org/licenses/by/3.0/) license (docs). \ No newline at end of file From 9887cb57b2e7ac99301310957934765f3288fd21 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Wed, 19 Sep 2012 01:03:05 +0100 Subject: [PATCH 102/284] Add a rake task to compile docs into static html. --- docs/Rakefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/Rakefile b/docs/Rakefile index b4e1d6d1..62b0139e 100644 --- a/docs/Rakefile +++ b/docs/Rakefile @@ -52,3 +52,8 @@ task :serve do exit end end + +task :build do + Bonsai.root_dir = Dir.pwd + Bonsai::Exporter.publish! +end From f51eca20f59ef3d9291b5df61ca357d7924872da Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Wed, 19 Sep 2012 01:10:47 +0100 Subject: [PATCH 103/284] Fix some issues with relative URLs on Github Pages. --- docs/content/2.download/default.yml | 6 +++--- docs/site.yml | 3 +++ docs/templates/index.liquid | 8 ++++---- docs/templates/shared/_head.liquid | 6 +++--- docs/templates/shared/_header.liquid | 4 ++-- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/docs/content/2.download/default.yml b/docs/content/2.download/default.yml index 9d69780a..54f4d78b 100644 --- a/docs/content/2.download/default.yml +++ b/docs/content/2.download/default.yml @@ -7,9 +7,9 @@ body: possible to build it for nearly any platform. Prebuilt binaries are available for Linux (64-bit x86) and OS X. - * [Download binary for 64-bit Linux](/download/linux_x86_64/jq) - * [Download binary for OS X](/download/osx_64/jq) - * [Download source](/download/source/jq.tgz) + * [Download binary for 64-bit Linux](linux_x86_64/jq) + * [Download binary for OS X](osx_64/jq) + * [Download source](source/jq.tgz) The binaries should just run, but you may need to make them executable first using: diff --git a/docs/site.yml b/docs/site.yml index b0d760ef..b34a9faa 100644 --- a/docs/site.yml +++ b/docs/site.yml @@ -2,6 +2,9 @@ jq_version: 1.0 +# Next line is needed for publishing to github pages +# root: '/jq' +root: '' footer: | This website is made with [Bonsai](http://www.tinytree.info) and diff --git a/docs/templates/index.liquid b/docs/templates/index.liquid index d2d06de5..aaff1c9f 100644 --- a/docs/templates/index.liquid +++ b/docs/templates/index.liquid @@ -7,7 +7,7 @@
- +
{{blurb | markdownify}} diff --git a/docs/templates/shared/_head.liquid b/docs/templates/shared/_head.liquid index acc6dfe2..5f2b7da8 100644 --- a/docs/templates/shared/_head.liquid +++ b/docs/templates/shared/_head.liquid @@ -1,12 +1,12 @@ {{headline}} | jq - - + + - + \ No newline at end of file diff --git a/docs/templates/shared/_header.liquid b/docs/templates/shared/_header.liquid index 82f778d7..020b130f 100644 --- a/docs/templates/shared/_header.liquid +++ b/docs/templates/shared/_header.liquid @@ -7,12 +7,12 @@ - jq + jq